diff --git a/BUILD.gn b/BUILD.gn index 21298781..19aee8c 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -24,6 +24,8 @@ import("//gpu/vulkan/features.gni") import("//media/gpu/args.gni") import("//media/media_options.gni") +import("//pdf/features.gni") +import("//printing/buildflags/buildflags.gni") import("//remoting/remoting_enable.gni") import("//third_party/closure_compiler/compile_js.gni") import("//tools/ipc_fuzzer/ipc_fuzzer.gni") @@ -163,8 +165,6 @@ "//ppapi/examples/video_capture", "//ppapi/examples/video_decode", "//ppapi/examples/video_encode", - "//printing:printing_unittests", - "//third_party/pdfium/samples:pdfium_test", "//third_party/vulkan-deps/spirv-tools/src:SPIRV-Tools", "//third_party/vulkan-deps/spirv-tools/src/test/fuzzers", "//tools/perf/clear_system_cache", @@ -272,6 +272,10 @@ deps += root_extra_deps + if (enable_basic_printing) { + deps += [ "//printing:printing_unittests" ] + } + if (enable_extensions) { deps += [ "//extensions:extensions_browsertests", @@ -281,6 +285,10 @@ ] } + if (enable_pdf) { + deps += [ "//third_party/pdfium/samples:pdfium_test" ] + } + if (enable_remoting) { deps += [ "//remoting:remoting_all" ] } @@ -774,7 +782,6 @@ if (((is_linux || is_chromeos) && !is_chromecast) || (is_win && use_libfuzzer) || (use_libfuzzer && is_mac)) { deps += [ - "//chrome/services/ipp_parser/public/cpp:fuzzers", "//testing/libfuzzer/fuzzers", "//third_party/freetype-testing:fuzzers", "//third_party/grpc:fuzzers", @@ -784,8 +791,12 @@ "//third_party/zlib/contrib/tests/fuzzers", ] + if (is_chromeos_ash) { + deps += [ "//chrome/services/ipp_parser/public/cpp:fuzzers" ] + } + # TODO(crbug.com/906751): Get the libFuzzer tests working on Windows. - # Disable them for now becaue they cause the Windows clang ToT builder to + # Disable them for now because they cause the Windows clang ToT builder to # fail. if (!is_win) { deps += [ "//testing/libfuzzer/tests:libfuzzer_tests" ]
diff --git a/DEPS b/DEPS index 49314c84..558e83f 100644 --- a/DEPS +++ b/DEPS
@@ -177,7 +177,7 @@ # luci-go CIPD package version. # Make sure the revision is uploaded by infra-packagers builder. # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console - 'luci_go': 'git_revision:5a038afb97f6b77e0fcefe1185317da216fced1f', + 'luci_go': 'git_revision:22d464e2f8f3bd2bd33f69fe819326d63f881008', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -209,7 +209,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '9e42ec30586dabd7afa3cd5cacf3b234c35b8d24', + 'skia_revision': 'f519ab8f093b8f308dd537c660b66f000a1de08a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -221,7 +221,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': '6f35e36686456ff453e15270b77eb429fc759981', + 'angle_revision': 'f871545d293f8fd55357eb2bcdaacea3cca9569f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -288,7 +288,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': 'c87525026921d80cffe27b08408ae318f614ec54', + 'devtools_frontend_revision': '7b45ea0188a7149d1580f5cbe2452cb563dea5a6', # 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. @@ -966,7 +966,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8c9a5b84cba7e5ebce5d97bea447c9662b1d43e9', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6b0a611c2c692684f94c0c3629f793feebd16b39', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1349,7 +1349,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f96c36dc3cf3507a03dfeb416c8b5d75abcea85e', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '7d6375fd3e2f91b5880195a9c02de2334a3fa0d4', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1547,7 +1547,7 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '22ba62ffe79c3881581ab430368bf3764d9533eb', - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3d799e0e9b08dc14a3efa2e130d288f6ca33d3d0', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@da00e22f60d1d150e6ee46d0e35528d39faaec7d', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a', @@ -1574,7 +1574,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a03bb38c0e771a0b404753b8e65250e98719870f', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '92bd9020afa45194f6d02dd9deba527a08cef21e', + Var('webrtc_git') + '/src.git' + '@' + '567e84726055d891cb66232f7c6a9d555318815c', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1601,7 +1601,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'BLHYEUi0wOYe5D_InWXtD8US7l_PMOrKHLuKt16L46QC', + 'version': 'PXrLb1Vy_W4AEPcc6NqgDemX073vvLhugmMa5syybtcC', }, ], 'dep_type': 'cipd', @@ -1611,7 +1611,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'P9wyIW02W7EqtyT9cZJj6g0HOcjRHAhN5KECwmhgRjUC', + 'version': 'oNxVMtwJ3j0wmiWBudkCQGv4Ke44tfCXvwWJ5wwlIDMC', }, ], 'dep_type': 'cipd', @@ -1621,7 +1621,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'qofjOtuSqFXnMKjZ9c7c-oVh9HeWjGW4h4F3y-vrfEkC', + 'version': '5_KCTT_-CKBlEN-y4_KRfb6Uxn3TzRM9bUuZFIVO5fUC', }, ], 'dep_type': 'cipd', @@ -1635,7 +1635,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0a9e379f114a73a7356a1b70713348034d3bccec', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@adfcd2446f1daa6804db5612b09665c15bfacc88', 'condition': 'checkout_src_internal', },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 032995cb..9159e4ad 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -4663,7 +4663,7 @@ """Check source code and known ascii text files for Windows style line endings. """ - known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$' + known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate|icon)$' file_inclusion_pattern = ( known_text_files, @@ -4688,6 +4688,16 @@ return [] +def CheckIconFilesForLicenseHeaders(input_api, output_api): + """Check that .icon files (which are fragments of C++) have license headers. + """ + + icon_files = (r'.*\.icon$',) + + icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files) + return input_api.canned_checks.CheckLicense( + input_api, output_api, source_file_filter=icons) + def CheckForUseOfChromeAppsDeprecations(input_api, output_api): """Check source code for use of Chrome App technologies being deprecated.
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc index c3d9898..1e74a63 100644 --- a/android_webview/browser/aw_contents_io_thread_client.cc +++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -375,39 +375,6 @@ "Android.WebView.ShouldInterceptRequest.InterceptionType", type); } -// Record UMA for the custom response status code for the intercepted requests -// where input stream is null. UMA is recorded only when the status codes and -// reason phrases are actually valid. -void RecordResponseStatusCode( - JNIEnv* env, - const std::unique_ptr<embedder_support::WebResourceResponse>& response) { - DCHECK(response); - DCHECK(!response->HasInputStream(env)); - - int status_code; - std::string reason_phrase; - bool status_info_valid = - response->GetStatusInfo(env, &status_code, &reason_phrase); - - if (!status_info_valid) { - // Status code is not necessary set properly in the response, - // e.g. Webview's WebResourceResponse(String, String, InputStream) [*] - // does not actually set the status code or the reason phrase. In this case - // we just record a zero status code. - // The other constructor (long version) or the #setStatusCodeAndReasonPhrase - // method does actually perform validity checks on status code and reason - // phrase arguments. - // [*] - // https://developer.android.com/reference/android/webkit/WebResourceResponse.html - status_code = 0; - } - - base::UmaHistogramSparse( - "Android.WebView.ShouldInterceptRequest.NullInputStream." - "ResponseStatusCode", - status_code); -} - std::unique_ptr<AwWebResourceInterceptResponse> NoInterceptRequest() { return nullptr; } @@ -441,15 +408,7 @@ if (!ret) return NoInterceptRequest(); - auto response = std::make_unique<AwWebResourceInterceptResponse>(ret); - if (!response->RaisedException(env) && response->HasResponse(env) && - !response->GetResponse(env)->HasInputStream(env)) { - // Only record UMA for cases where the input stream is null (see - // crbug.com/974273). - RecordResponseStatusCode(env, response->GetResponse(env)); - } - - return response; + return std::make_unique<AwWebResourceInterceptResponse>(ret); } } // namespace
diff --git a/apps/DIR_METADATA b/apps/DIR_METADATA index 5cc4c774..e2c4d38a 100644 --- a/apps/DIR_METADATA +++ b/apps/DIR_METADATA
@@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Platform>Apps"
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index c9cc78e..cb4cd6d 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -919,28 +919,28 @@ "system/accessibility/floating_menu_button.h", "system/accessibility/floating_menu_utils.cc", "system/accessibility/floating_menu_utils.h", - "system/accessibility/select_to_speak_constants.h", - "system/accessibility/select_to_speak_menu_bubble_controller.cc", - "system/accessibility/select_to_speak_menu_bubble_controller.h", - "system/accessibility/select_to_speak_menu_view.cc", - "system/accessibility/select_to_speak_menu_view.h", - "system/accessibility/select_to_speak_metrics_utils.h", - "system/accessibility/select_to_speak_speed_bubble_controller.cc", - "system/accessibility/select_to_speak_speed_bubble_controller.h", - "system/accessibility/select_to_speak_speed_view.cc", - "system/accessibility/select_to_speak_speed_view.h", - "system/accessibility/select_to_speak_tray.cc", - "system/accessibility/select_to_speak_tray.h", - "system/accessibility/switch_access_back_button_bubble_controller.cc", - "system/accessibility/switch_access_back_button_bubble_controller.h", - "system/accessibility/switch_access_back_button_view.cc", - "system/accessibility/switch_access_back_button_view.h", - "system/accessibility/switch_access_menu_bubble_controller.cc", - "system/accessibility/switch_access_menu_bubble_controller.h", - "system/accessibility/switch_access_menu_button.cc", - "system/accessibility/switch_access_menu_button.h", - "system/accessibility/switch_access_menu_view.cc", - "system/accessibility/switch_access_menu_view.h", + "system/accessibility/select_to_speak/select_to_speak_constants.h", + "system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.cc", + "system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h", + "system/accessibility/select_to_speak/select_to_speak_menu_view.cc", + "system/accessibility/select_to_speak/select_to_speak_menu_view.h", + "system/accessibility/select_to_speak/select_to_speak_metrics_utils.h", + "system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.cc", + "system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h", + "system/accessibility/select_to_speak/select_to_speak_speed_view.cc", + "system/accessibility/select_to_speak/select_to_speak_speed_view.h", + "system/accessibility/select_to_speak/select_to_speak_tray.cc", + "system/accessibility/select_to_speak/select_to_speak_tray.h", + "system/accessibility/switch_access/switch_access_back_button_bubble_controller.cc", + "system/accessibility/switch_access/switch_access_back_button_bubble_controller.h", + "system/accessibility/switch_access/switch_access_back_button_view.cc", + "system/accessibility/switch_access/switch_access_back_button_view.h", + "system/accessibility/switch_access/switch_access_menu_bubble_controller.cc", + "system/accessibility/switch_access/switch_access_menu_bubble_controller.h", + "system/accessibility/switch_access/switch_access_menu_button.cc", + "system/accessibility/switch_access/switch_access_menu_button.h", + "system/accessibility/switch_access/switch_access_menu_view.cc", + "system/accessibility/switch_access/switch_access_menu_view.h", "system/accessibility/tray_accessibility.cc", "system/accessibility/tray_accessibility.h", "system/accessibility/unified_accessibility_detailed_view_controller.cc", @@ -2232,11 +2232,11 @@ "system/accessibility/autoclick_menu_bubble_controller_unittest.cc", "system/accessibility/dictation_button_tray_unittest.cc", "system/accessibility/floating_accessibility_controller_unittest.cc", - "system/accessibility/select_to_speak_menu_bubble_controller_unittest.cc", - "system/accessibility/select_to_speak_speed_bubble_controller_unittest.cc", - "system/accessibility/select_to_speak_tray_unittest.cc", - "system/accessibility/switch_access_back_button_bubble_controller_unittest.cc", - "system/accessibility/switch_access_menu_bubble_controller_unittest.cc", + "system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller_unittest.cc", + "system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller_unittest.cc", + "system/accessibility/select_to_speak/select_to_speak_tray_unittest.cc", + "system/accessibility/switch_access/switch_access_back_button_bubble_controller_unittest.cc", + "system/accessibility/switch_access/switch_access_menu_bubble_controller_unittest.cc", "system/accessibility/tray_accessibility_unittest.cc", "system/audio/unified_audio_detailed_view_controller_unittest.cc", "system/bluetooth/bluetooth_notification_controller_unittest.cc", @@ -2703,6 +2703,8 @@ "metrics/task_switch_time_tracker_test_api.h", "metrics/user_metrics_recorder_test_api.cc", "metrics/user_metrics_recorder_test_api.h", + "projector/test/mock_projector_client.cc", + "projector/test/mock_projector_client.h", "projector/test/mock_projector_metadata_controller.cc", "projector/test/mock_projector_metadata_controller.h", "projector/test/mock_projector_ui_controller.cc",
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc index 0aa44df..85b0d33 100644 --- a/ash/accelerators/accelerator_controller_impl.cc +++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -2505,6 +2505,14 @@ HandleTopWindowMinimizeOnBack(); break; } + + // Reset any in progress composition. + if (::features::IsImprovedKeyboardShortcutsEnabled()) { + auto* input_method = + Shell::Get()->window_tree_host_manager()->input_method(); + + input_method->CancelComposition(input_method->GetTextInputClient()); + } } bool AcceleratorControllerImpl::ShouldActionConsumeKeyEvent(
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index d95b046d..aec6d76 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -79,6 +79,8 @@ #include "ui/base/ime/chromeos/fake_ime_keyboard.h" #include "ui/base/ime/chromeos/ime_keyboard.h" #include "ui/base/ime/chromeos/mock_input_method_manager.h" +#include "ui/base/ime/init/input_method_factory.h" +#include "ui/base/ime/mock_input_method.h" #include "ui/base/ui_base_features.h" #include "ui/display/manager/display_manager.h" #include "ui/display/screen.h" @@ -2143,6 +2145,62 @@ EXPECT_TRUE(ProcessInController(accelerator)); } +class AcceleratorControllerInputMethodTest : public AcceleratorControllerTest { + public: + AcceleratorControllerInputMethodTest() = default; + ~AcceleratorControllerInputMethodTest() override = default; + + class AcceleratorMockInputMethod : public ui::MockInputMethod { + public: + AcceleratorMockInputMethod() : ui::MockInputMethod(nullptr) {} + void CancelComposition(const ui::TextInputClient* client) override { + cancel_composition_call_count++; + } + + uint32_t cancel_composition_call_count = 0; + }; + + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + ::features::kImprovedKeyboardShortcuts); + + // Setup the mock input method to capture the calls to + // |CancelCompositionAfterAccelerator|. Ownersship is passed to + // ui::SetUpInputMethodForTesting(). + mock_input_ = new AcceleratorMockInputMethod(); + ui::SetUpInputMethodForTesting(mock_input_); + AcceleratorControllerTest::SetUp(); + } + + protected: + AcceleratorMockInputMethod* mock_input_ = nullptr; // Not owned. + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// In some layouts positional accelerators can be on dead/compose keys. To +// ensure that the input method is not left in a partially composed state +// the composition state is reset when an accelerator is matched. +TEST_F(AcceleratorControllerInputMethodTest, AcceleratorClearsComposition) { + EXPECT_EQ(0u, mock_input_->cancel_composition_call_count); + + // An acclerator that isn't recognized will not cause composition to be + // cancelled. + ui::Accelerator unknown_accelerator(ui::VKEY_OEM_MINUS, ui::EF_NONE); + EXPECT_FALSE(controller_->IsRegistered(unknown_accelerator)); + EXPECT_FALSE(ProcessInController(unknown_accelerator)); + EXPECT_EQ(0u, mock_input_->cancel_composition_call_count); + + // A matching accelerator should cause CancelCompositionAfterAccelerator() to + // be called. + ui::Accelerator accelerator(ui::VKEY_OEM_MINUS, + ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN); + EXPECT_TRUE(controller_->IsRegistered(accelerator)); + EXPECT_TRUE(ProcessInController(accelerator)); + EXPECT_EQ(1u, mock_input_->cancel_composition_call_count); +} + namespace { // TODO(crbug.com/1179893): Remove once the feature is enabled permantently.
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc index b82f8de4..0862ca82 100644 --- a/ash/accessibility/accessibility_controller_impl.cc +++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -38,8 +38,8 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/system/accessibility/accessibility_feature_disable_dialog.h" #include "ash/system/accessibility/floating_accessibility_controller.h" -#include "ash/system/accessibility/select_to_speak_menu_bubble_controller.h" -#include "ash/system/accessibility/switch_access_menu_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h" #include "ash/system/power/backlights_forced_off_setter.h" #include "ash/system/power/power_status.h" #include "ash/system/power/scoped_backlights_forced_off.h"
diff --git a/ash/ambient/ambient_photo_controller.cc b/ash/ambient/ambient_photo_controller.cc index a4ddbce..30d0fec 100644 --- a/ash/ambient/ambient_photo_controller.cc +++ b/ash/ambient/ambient_photo_controller.cc
@@ -428,6 +428,7 @@ num_callbacks, base::BindOnce(&AmbientPhotoController::OnAllPhotoDecoded, weak_factory_.GetWeakPtr(), from_downloading, + cache_entry.details ? *cache_entry.details : std::string(), /*hash=*/base::SHA1HashString(*cache_entry.image))); DecodePhotoRawData(from_downloading, @@ -465,6 +466,7 @@ } void AmbientPhotoController::OnAllPhotoDecoded(bool from_downloading, + const std::string& details, const std::string& hash) { if (image_.isNull()) { LOG(WARNING) << "Image decoding failed"; @@ -489,8 +491,7 @@ PhotoWithDetails detailed_photo; detailed_photo.photo = image_; detailed_photo.related_photo = related_image_; - if (cache_entry_.details) - detailed_photo.details = *cache_entry_.details; + detailed_photo.details = details; detailed_photo.hash = hash; ResetImageData();
diff --git a/ash/ambient/ambient_photo_controller.h b/ash/ambient/ambient_photo_controller.h index f463fd023..1880513 100644 --- a/ash/ambient/ambient_photo_controller.h +++ b/ash/ambient/ambient_photo_controller.h
@@ -134,7 +134,9 @@ base::RepeatingClosure on_done, const gfx::ImageSkia& image); - void OnAllPhotoDecoded(bool from_downloading, const std::string& hash); + void OnAllPhotoDecoded(bool from_downloading, + const std::string& details, + const std::string& hash); void StartDownloadingWeatherConditionIcon( const absl::optional<WeatherInfo>& weather_info);
diff --git a/ash/ambient/ambient_photo_controller_unittest.cc b/ash/ambient/ambient_photo_controller_unittest.cc index 94f4775b..f2853c59 100644 --- a/ash/ambient/ambient_photo_controller_unittest.cc +++ b/ash/ambient/ambient_photo_controller_unittest.cc
@@ -152,6 +152,22 @@ photo_controller()->StopScreenUpdate(); } +// Tests that image details is correctly set. +TEST_F(AmbientPhotoControllerTest, ShouldSetDetailsCorrectly) { + // Start to refresh images. + photo_controller()->StartScreenUpdate(); + FastForwardToNextImage(); + PhotoWithDetails image = + photo_controller()->ambient_backend_model()->GetNextImage(); + EXPECT_FALSE(image.IsNull()); + + // Fake details defined in fake_ambient_backend_controller_impl.cc. + EXPECT_EQ(image.details, "fake-photo-attribution"); + + // Stop to refresh images. + photo_controller()->StopScreenUpdate(); +} + // Test that image is saved. TEST_F(AmbientPhotoControllerTest, ShouldSaveImagesOnDisk) { // Start to refresh images. It will download two images immediately and write @@ -255,6 +271,28 @@ EXPECT_FALSE(image.IsNull()); } +// Test that image details is read from disk. +TEST_F(AmbientPhotoControllerTest, ShouldPopulateDetailsWhenReadFromCache) { + FetchImage(); + FastForwardToNextImage(); + // Topics is empty. Will read from cache, which is empty. + auto image = photo_controller()->ambient_backend_model()->GetCurrentImage(); + EXPECT_TRUE(image.IsNull()); + + // Save a file to check if it gets read for display. + std::string data("cached image"); + std::string details("image details"); + WriteCacheDataBlocking(/*cache_index=*/0, &data, &details); + + // Reset variables in photo controller. + photo_controller()->StopScreenUpdate(); + FetchImage(); + FastForwardToNextImage(); + image = photo_controller()->ambient_backend_model()->GetCurrentImage(); + EXPECT_FALSE(image.IsNull()); + EXPECT_EQ(image.details, details); +} + // Test that image is read from disk when image decoding failed. TEST_F(AmbientPhotoControllerTest, ShouldReadCacheWhenImageDecodingFailed) { SetDecodePhotoImage(gfx::ImageSkia());
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn index 8da11b1..2196150 100644 --- a/ash/app_list/BUILD.gn +++ b/ash/app_list/BUILD.gn
@@ -28,6 +28,12 @@ "bubble/app_list_bubble_event_filter.h", "bubble/app_list_bubble_view.cc", "bubble/app_list_bubble_view.h", + "bubble/bubble_apps_page.cc", + "bubble/bubble_apps_page.h", + "bubble/bubble_assistant_page.cc", + "bubble/bubble_assistant_page.h", + "bubble/bubble_search_page.cc", + "bubble/bubble_search_page.h", "home_launcher_animation_info.h", "paged_view_structure.cc", "paged_view_structure.h",
diff --git a/ash/app_list/bubble/app_list_bubble_unittest.cc b/ash/app_list/bubble/app_list_bubble_unittest.cc index 8056fdc..60ddd33f 100644 --- a/ash/app_list/bubble/app_list_bubble_unittest.cc +++ b/ash/app_list/bubble/app_list_bubble_unittest.cc
@@ -14,6 +14,7 @@ #include "ash/shelf/shelf_navigation_widget.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" +#include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/display/display.h" @@ -43,6 +44,13 @@ } ~AppListBubbleTest() override = default; + // testing::Test: + void SetUp() override { + AshTestBase::SetUp(); + // Use a realistic screen size so the default size bubble will fit. + UpdateDisplay("1366x768"); + } + // Returns the AppListBubble instance. Use this instead of creating a new // AppListBubble instance in each test to avoid situations where two bubbles // exist at the same time (the per-test one and the "production" one).
diff --git a/ash/app_list/bubble/app_list_bubble_view.cc b/ash/app_list/bubble/app_list_bubble_view.cc index 08e2f39..65ca296 100644 --- a/ash/app_list/bubble/app_list_bubble_view.cc +++ b/ash/app_list/bubble/app_list_bubble_view.cc
@@ -6,6 +6,9 @@ #include <memory> +#include "ash/app_list/bubble/bubble_apps_page.h" +#include "ash/app_list/bubble/bubble_assistant_page.h" +#include "ash/app_list/bubble/bubble_search_page.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shelf/shelf.h" @@ -16,7 +19,7 @@ #include "ui/display/screen.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/bubble/bubble_border.h" -#include "ui/views/controls/label.h" +#include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/layout/box_layout.h" @@ -76,12 +79,38 @@ std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical)); layout->set_cross_axis_alignment(BoxLayout::CrossAxisAlignment::kStretch); - // TODO(https://crbug.com/1204551): Create real contents. - AddChildView(std::make_unique<views::Label>(u"Placeholder")); + // TODO(https://crbug.com/1204551): Replace with real search box. auto* textfield = AddChildView(std::make_unique<views::Textfield>()); SetInitiallyFocusedView(textfield); + + // TODO(https://crbug.com/1204551): Remove when search box is hooked up. + AddChildView(std::make_unique<views::MdTextButton>( + base::BindRepeating(&AppListBubbleView::FlipPage, base::Unretained(this)), + u"Flip page")); + + apps_page_ = AddChildView(std::make_unique<BubbleAppsPage>()); + + search_page_ = AddChildView(std::make_unique<BubbleSearchPage>()); + search_page_->SetVisible(false); + + assistant_page_ = AddChildView(std::make_unique<BubbleAssistantPage>()); + assistant_page_->SetVisible(false); } AppListBubbleView::~AppListBubbleView() = default; +gfx::Size AppListBubbleView::CalculatePreferredSize() const { + constexpr gfx::Size kDefaultSizeDips(600, 550); + // TODO(https://crbug.com/1210522): Adjust size based on screen resolution. + return kDefaultSizeDips; +} + +void AppListBubbleView::FlipPage() { + ++visible_page_; + visible_page_ %= 3; + apps_page_->SetVisible(visible_page_ == 0); + search_page_->SetVisible(visible_page_ == 1); + assistant_page_->SetVisible(visible_page_ == 2); +} + } // namespace ash
diff --git a/ash/app_list/bubble/app_list_bubble_view.h b/ash/app_list/bubble/app_list_bubble_view.h index 7adfdd2..7f64252 100644 --- a/ash/app_list/bubble/app_list_bubble_view.h +++ b/ash/app_list/bubble/app_list_bubble_view.h
@@ -14,6 +14,9 @@ namespace ash { +class BubbleAppsPage; +class BubbleAssistantPage; +class BubbleSearchPage; enum class ShelfAlignment; // Contains the views for the bubble version of the launcher. @@ -25,6 +28,21 @@ AppListBubbleView(const AppListBubbleView&) = delete; AppListBubbleView& operator=(const AppListBubbleView&) = delete; ~AppListBubbleView() override; + + // views::View: + gfx::Size CalculatePreferredSize() const override; + + private: + // Flips between the apps, search and assistant pages. + // TODO(https://crbug.com/1204551): Delete this when search box is hooked up. + void FlipPage(); + + // TODO(https://crbug.com/1204551): Delete this when search box is hooked up. + int visible_page_ = 0; + + BubbleAppsPage* apps_page_ = nullptr; + BubbleSearchPage* search_page_ = nullptr; + BubbleAssistantPage* assistant_page_ = nullptr; }; } // namespace ash
diff --git a/ash/app_list/bubble/bubble_apps_page.cc b/ash/app_list/bubble/bubble_apps_page.cc new file mode 100644 index 0000000..59837e0 --- /dev/null +++ b/ash/app_list/bubble/bubble_apps_page.cc
@@ -0,0 +1,86 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/app_list/bubble/bubble_apps_page.h" + +#include <limits> +#include <memory> +#include <utility> + +#include "ui/gfx/text_constants.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/layout/box_layout.h" + +using views::BoxLayout; + +namespace ash { + +BubbleAppsPage::BubbleAppsPage() { + SetUseDefaultFillLayout(true); + + // The entire page scrolls. + auto* scroll = AddChildView(std::make_unique<views::ScrollView>()); + scroll->ClipHeightTo(0, std::numeric_limits<int>::max()); + scroll->SetDrawOverflowIndicator(false); + scroll->SetHorizontalScrollBarMode( + views::ScrollView::ScrollBarMode::kDisabled); + + auto scroll_contents = std::make_unique<views::View>(); + scroll_contents->SetLayoutManager( + std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical)); + + // TODO(https://crbug.com/1204551): Localized strings. + // TODO(https://crbug.com/1204551): Styling. + auto* continue_label = scroll_contents->AddChildView( + std::make_unique<views::Label>(u"Continue")); + continue_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + + auto* continue_section = + scroll_contents->AddChildView(std::make_unique<views::View>()); + // TODO(https://crbug.com/1204551): Extract SimpleGridLayout from + // HoldingSpaceItemChipsContainer and use it here. + const int kContinueSpacing = 16; + auto* continue_layout = + continue_section->SetLayoutManager(std::make_unique<BoxLayout>( + BoxLayout::Orientation::kVertical, gfx::Insets(), kContinueSpacing)); + continue_layout->set_cross_axis_alignment( + BoxLayout::CrossAxisAlignment::kStretch); + for (int i = 0; i < 4; ++i) { + continue_section->AddChildView(std::make_unique<views::Label>(u"Task")); + } + + // TODO(https://crbug.com/1204551): Replace with real recent apps view. + auto* recent_apps = + scroll_contents->AddChildView(std::make_unique<views::View>()); + const int kRecentAppsSpacing = 16; + auto* recent_apps_layout = + recent_apps->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), + kRecentAppsSpacing)); + recent_apps_layout->set_main_axis_alignment( + views::BoxLayout::MainAxisAlignment::kCenter); + for (int i = 0; i < 5; ++i) { + recent_apps->AddChildView(std::make_unique<views::Label>(u"Recent")); + } + + // TODO(https://crbug.com/1204551): Replace with real apps grid. For now, + // create enough labels to force the scroll view to scroll. + auto* all_apps = + scroll_contents->AddChildView(std::make_unique<views::View>()); + const int kAllAppsSpacing = 16; + all_apps->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, gfx::Insets(), + kAllAppsSpacing)); + for (int i = 0; i < 20; ++i) { + all_apps->AddChildView(std::make_unique<views::Label>(u"App")); + } + + scroll->SetContents(std::move(scroll_contents)); +} + +BubbleAppsPage::~BubbleAppsPage() = default; + +} // namespace ash
diff --git a/ash/app_list/bubble/bubble_apps_page.h b/ash/app_list/bubble/bubble_apps_page.h new file mode 100644 index 0000000..bff54a64 --- /dev/null +++ b/ash/app_list/bubble/bubble_apps_page.h
@@ -0,0 +1,28 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +// The default page for the app list bubble / clamshell launcher. Contains a +// scroll view with: +// - Continue section with recent tasks and recent apps +// - Grid of all apps +// Does not include the search box, which is owned by a parent view. +class ASH_EXPORT BubbleAppsPage : public views::View { + public: + BubbleAppsPage(); + BubbleAppsPage(const BubbleAppsPage&) = delete; + BubbleAppsPage& operator=(const BubbleAppsPage&) = delete; + ~BubbleAppsPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_assistant_page.cc b/ash/app_list/bubble/bubble_assistant_page.cc new file mode 100644 index 0000000..6079c70 --- /dev/null +++ b/ash/app_list/bubble/bubble_assistant_page.cc
@@ -0,0 +1,32 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/app_list/bubble/bubble_assistant_page.h" + +#include <memory> +#include <utility> + +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" + +using views::BoxLayout; + +namespace ash { + +BubbleAssistantPage::BubbleAssistantPage() { + SetLayoutManager( + std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical)); + + // TODO(https://crbug.com/1204551): Sort out whether this view needs its own + // search box, or if it can use the one owned by the parent. The assistant + // page in the tablet launcher owns its own search box, but that may be a side + // effect of animations or the historical need to host assistant in a widget. + + // TODO(https://crbug.com/1204551): Embed the assistant. + AddChildView(std::make_unique<views::Label>(u"Assistant")); +} + +BubbleAssistantPage::~BubbleAssistantPage() = default; + +} // namespace ash
diff --git a/ash/app_list/bubble/bubble_assistant_page.h b/ash/app_list/bubble/bubble_assistant_page.h new file mode 100644 index 0000000..ab3c2f82 --- /dev/null +++ b/ash/app_list/bubble/bubble_assistant_page.h
@@ -0,0 +1,24 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +// The assistant page for the app list bubble / clamshell launcher. +class ASH_EXPORT BubbleAssistantPage : public views::View { + public: + BubbleAssistantPage(); + BubbleAssistantPage(const BubbleAssistantPage&) = delete; + BubbleAssistantPage& operator=(const BubbleAssistantPage&) = delete; + ~BubbleAssistantPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_search_page.cc b/ash/app_list/bubble/bubble_search_page.cc new file mode 100644 index 0000000..e00e4b7f --- /dev/null +++ b/ash/app_list/bubble/bubble_search_page.cc
@@ -0,0 +1,49 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/app_list/bubble/bubble_search_page.h" + +#include <limits> +#include <memory> +#include <utility> + +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/layout/box_layout.h" + +using views::BoxLayout; + +namespace ash { + +BubbleSearchPage::BubbleSearchPage() { + SetUseDefaultFillLayout(true); + + // The entire page scrolls. + auto* scroll = AddChildView(std::make_unique<views::ScrollView>()); + scroll->ClipHeightTo(0, std::numeric_limits<int>::max()); + scroll->SetDrawOverflowIndicator(false); + scroll->SetHorizontalScrollBarMode( + views::ScrollView::ScrollBarMode::kDisabled); + + auto scroll_contents = std::make_unique<views::View>(); + scroll_contents->SetLayoutManager( + std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical)); + + // TODO(https://crbug.com/1204551): Replace with real search results. For now, + // create enough labels to force the scroll view to scroll. + auto* results = + scroll_contents->AddChildView(std::make_unique<views::View>()); + const int kSpacing = 16; + results->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, gfx::Insets(), kSpacing)); + for (int i = 0; i < 20; ++i) { + results->AddChildView(std::make_unique<views::Label>(u"Result")); + } + + scroll->SetContents(std::move(scroll_contents)); +} + +BubbleSearchPage::~BubbleSearchPage() = default; + +} // namespace ash
diff --git a/ash/app_list/bubble/bubble_search_page.h b/ash/app_list/bubble/bubble_search_page.h new file mode 100644 index 0000000..d55acbb --- /dev/null +++ b/ash/app_list/bubble/bubble_search_page.h
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +// The search results page for the app list bubble / clamshell launcher. +// Contains a scrolling list of search results. Does not include the search box, +// which is owned by a parent view. +class ASH_EXPORT BubbleSearchPage : public views::View { + public: + BubbleSearchPage(); + BubbleSearchPage(const BubbleSearchPage&) = delete; + BubbleSearchPage& operator=(const BubbleSearchPage&) = delete; + ~BubbleSearchPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 8fe989e1..737c272 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -3591,6 +3591,93 @@ <message name="IDS_ASH_SHIMLESS_RMA_APP_TITLE" translateable="false" desc="The title of shimless RMA flow SWA. Shimless RMA guides repair technicians through step-by-step repair flow."> Shimless RMA </message> + + <!-- Strings for Projector--> + + <message name="IDS_KEY_IDEA_BUTTON" desc="The name for the key idea button."> + Add key idea + </message> + + <message name="IDS_LASER_POINTER_BUTTON" desc="The name for the laser pointer button."> + Laser pointer + </message> + + <message name="IDS_MARKER_BUTTON" desc="The name for the marker button."> + Marker + </message> + + <message name="IDS_INK_PEN_BUTTON" desc="The name for the ink pen button."> + Ink pen + </message> + + <message name="IDS_MARKER_PEN_BUTTON" desc="The name for the marker pen button."> + Marker pen + </message> + + <message name="IDS_MARKER_COLOR_BUTTON" desc="The name for the marker color button."> + <ph name="COLOR_PARAMETER">$1<ex>blue</ex></ph> marker color + </message> + + <message name="IDS_UNDO_BUTTON" desc="The name for the undo button."> + Undo + </message> + + <message name="IDS_CLEAR_ALL_MARKERS_BUTTON" desc="The name for the clear all markers button."> + Clear all markers + </message> + + <message name="IDS_EXPAND_MARKER_TOOLS_BUTTON" desc="The name for the expand marker tools button."> + Expand marker tools + </message> + + <message name="IDS_COLLAPSE_MARKER_TOOLS_BUTTON" desc="The name for the collapse marker tools button."> + Collapse marker tools + </message> + + <message name="IDS_START_MAGNIFIER_BUTTON" desc="The name for the start magnifier button."> + Start magnifier + </message> + + <message name="IDS_STOP_MAGNIFIER_BUTTON" desc="The name for the stop magnifier button."> + Stop magnifier + </message> + + <message name="IDS_START_SELFIE_CAMERA_BUTTON" desc="The name for the start selfie camera button."> + Start selfie camera + </message> + + <message name="IDS_STOP_SELFIE_CAMERA_BUTTON" desc="The name for the stop selfie camera button."> + Stop selfie camera + </message> + + <message name="IDS_START_CLOSED_CAPTIONS_BUTTON" desc="The name for start closed captions button."> + Start closed captions + </message> + + <message name="IDS_STOP_CLOSED_CAPTIONS_BUTTON" desc="The name for stop closed captions button."> + Stop closed captions + </message> + + <message name="IDS_BAR_LOCATION_BUTTON" desc="The name for the bar location button."> + Toggle bar location + </message> + + <message name="IDS_BLACK_COLOR_BUTTON" desc="The name for the black marker button."> + Black + </message> + + <message name="IDS_WHITE_COLOR_BUTTON" desc="The name for the white marker button."> + White + </message> + + <message name="IDS_BLUE_COLOR_BUTTON" desc="The name for the blue marker button."> + Blue + </message> + + <message name="IDS_UNKNOWN_COLOR_BUTTON" desc="The name for the unknown marker button."> + Unknown + </message> + </messages> </release> </grit>
diff --git a/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1 new file mode 100644 index 0000000..dba4d64a0 --- /dev/null +++ b/ash/ash_strings_grd/IDS_BAR_LOCATION_BUTTON.png.sha1
@@ -0,0 +1 @@ +a5bd6a8c1710652534a9ec6baa5d2821e3e3e8bf \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_BLACK_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_BLACK_COLOR_BUTTON.png.sha1 new file mode 100644 index 0000000..c925577f --- /dev/null +++ b/ash/ash_strings_grd/IDS_BLACK_COLOR_BUTTON.png.sha1
@@ -0,0 +1 @@ +27f4eb1d76a2a686a79f93524334a22d3dfda12b \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_BLUE_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_BLUE_COLOR_BUTTON.png.sha1 new file mode 100644 index 0000000..26cb665 --- /dev/null +++ b/ash/ash_strings_grd/IDS_BLUE_COLOR_BUTTON.png.sha1
@@ -0,0 +1 @@ +153471238880eb515a2340f5076228ca187a37d0 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1 new file mode 100644 index 0000000..13e3b254 --- /dev/null +++ b/ash/ash_strings_grd/IDS_CLEAR_ALL_MARKERS_BUTTON.png.sha1
@@ -0,0 +1 @@ +876fcbe8ce6916f81d7f49ed105e24e424ffb729 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1 new file mode 100644 index 0000000..7bc6983a --- /dev/null +++ b/ash/ash_strings_grd/IDS_COLLAPSE_MARKER_TOOLS_BUTTON.png.sha1
@@ -0,0 +1 @@ +44f37b74dffb0d2387e16f998afe731ffbbccadd \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1 new file mode 100644 index 0000000..b846563 --- /dev/null +++ b/ash/ash_strings_grd/IDS_EXPAND_MARKER_TOOLS_BUTTON.png.sha1
@@ -0,0 +1 @@ +79d4d0863a36aa153cc92176eb0ce9e6764404e5 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_EXTENSIONS_ENABLE_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_EXTENSIONS_ENABLE_BUTTON.png.sha1 new file mode 100644 index 0000000..301528a --- /dev/null +++ b/ash/ash_strings_grd/IDS_EXTENSIONS_ENABLE_BUTTON.png.sha1
@@ -0,0 +1 @@ +f2a24389c19c6a880a5f1e7266d47e6e70b874b0 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1 new file mode 100644 index 0000000..be90797 --- /dev/null +++ b/ash/ash_strings_grd/IDS_INK_PEN_BUTTON.png.sha1
@@ -0,0 +1 @@ +9621a79948d5f9804d5d24213a3698b8f2a0b5e9 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1 new file mode 100644 index 0000000..624e8bd --- /dev/null +++ b/ash/ash_strings_grd/IDS_KEY_IDEA_BUTTON.png.sha1
@@ -0,0 +1 @@ +4640217c15a4b968f27094c0a70fa499b749ae43 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1 new file mode 100644 index 0000000..9190f58 --- /dev/null +++ b/ash/ash_strings_grd/IDS_LASER_POINTER_BUTTON.png.sha1
@@ -0,0 +1 @@ +7ff2ddde7110785a542df75117bf740e8ec9cde4 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1 new file mode 100644 index 0000000..3dfccb7bc --- /dev/null +++ b/ash/ash_strings_grd/IDS_MARKER_BUTTON.png.sha1
@@ -0,0 +1 @@ +3007dfdbbbb2ac01f7dcb91ff4b035ea6efdb118 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1 new file mode 100644 index 0000000..c889abf7 --- /dev/null +++ b/ash/ash_strings_grd/IDS_MARKER_COLOR_BUTTON.png.sha1
@@ -0,0 +1 @@ +a22f2f1da5d6764d0d0752aacfb1a4905f6bb7f7 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1 new file mode 100644 index 0000000..c2e3a67 --- /dev/null +++ b/ash/ash_strings_grd/IDS_MARKER_PEN_BUTTON.png.sha1
@@ -0,0 +1 @@ +6e0aad7230b25193689822690661cbb1eaebab70 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1 new file mode 100644 index 0000000..2f496cb9 --- /dev/null +++ b/ash/ash_strings_grd/IDS_START_CLOSED_CAPTIONS_BUTTON.png.sha1
@@ -0,0 +1 @@ +b33e78eefa35815bc615bff941bfe44ef7824df1 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1 new file mode 100644 index 0000000..25e3b07 --- /dev/null +++ b/ash/ash_strings_grd/IDS_START_MAGNIFIER_BUTTON.png.sha1
@@ -0,0 +1 @@ +e7a83d97040706131735a3559eb9a0e1c437557d \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1 new file mode 100644 index 0000000..5e4f75b --- /dev/null +++ b/ash/ash_strings_grd/IDS_START_SELFIE_CAMERA_BUTTON.png.sha1
@@ -0,0 +1 @@ +a6cc5126c2040f2bf221b54721c48dd8d2a421fd \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1 new file mode 100644 index 0000000..82882b9 --- /dev/null +++ b/ash/ash_strings_grd/IDS_STOP_CLOSED_CAPTIONS_BUTTON.png.sha1
@@ -0,0 +1 @@ +9d06341f57fee98c4366bc3f85cf950525c985cb \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1 new file mode 100644 index 0000000..4031133b --- /dev/null +++ b/ash/ash_strings_grd/IDS_STOP_MAGNIFIER_BUTTON.png.sha1
@@ -0,0 +1 @@ +44eda6d367523f4fc69e9ebd19cba56f4ea70bb2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1 new file mode 100644 index 0000000..64141e4 --- /dev/null +++ b/ash/ash_strings_grd/IDS_STOP_SELFIE_CAMERA_BUTTON.png.sha1
@@ -0,0 +1 @@ +26e40ae7b76394489afbc0b6ef1b5ac5e6555b9d \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1 new file mode 100644 index 0000000..5157fb6 --- /dev/null +++ b/ash/ash_strings_grd/IDS_UNDO_BUTTON.png.sha1
@@ -0,0 +1 @@ +29432a50d1c76fc76d230c165636a7947533c194 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_UNKNOWN_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_UNKNOWN_COLOR_BUTTON.png.sha1 new file mode 100644 index 0000000..dc50e80d --- /dev/null +++ b/ash/ash_strings_grd/IDS_UNKNOWN_COLOR_BUTTON.png.sha1
@@ -0,0 +1 @@ +122ce269326d14a6c0c8f575b6d9b4640a4c42af \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_WHITE_COLOR_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_WHITE_COLOR_BUTTON.png.sha1 new file mode 100644 index 0000000..1cf6cd71 --- /dev/null +++ b/ash/ash_strings_grd/IDS_WHITE_COLOR_BUTTON.png.sha1
@@ -0,0 +1 @@ +7693f2f43f03bc9f6b05134bbb6d0c8f207f8b34 \ No newline at end of file
diff --git a/ash/content/shortcut_customization_ui/resources/BUILD.gn b/ash/content/shortcut_customization_ui/resources/BUILD.gn index ea809e3..43b86f06 100644 --- a/ash/content/shortcut_customization_ui/resources/BUILD.gn +++ b/ash/content/shortcut_customization_ui/resources/BUILD.gn
@@ -12,10 +12,12 @@ preprocessed_gen_manifest = "preprocessed_gen_manifest.json" polymer_element_files = [ - "shortcut_customization_app.js", - "shortcut_input.js", + "accessibility_shortcuts_page.js", + "android_shortcuts_page.js", "browser_shortcuts_page.js", "chromeos_shortcuts_page.js", + "shortcut_customization_app.js", + "shortcut_input.js", ] generate_grd("build_grd") { @@ -64,6 +66,20 @@ ] } +js_library("android_shortcuts_page") { + deps = [ + ":shortcut_input", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] +} + +js_library("accessibility_shortcuts_page") { + deps = [ + ":shortcut_input", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] +} + preprocess_if_expr("preprocess_generated") { deps = [ ":web_components" ] in_folder = target_gen_dir
diff --git a/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.html b/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.html new file mode 100644 index 0000000..2f167906 --- /dev/null +++ b/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.html
@@ -0,0 +1,2 @@ +<div>Accessibility</div> +<shortcut-input></shortcut-input> \ No newline at end of file
diff --git a/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.js b/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.js new file mode 100644 index 0000000..286b52e --- /dev/null +++ b/ash/content/shortcut_customization_ui/resources/accessibility_shortcuts_page.js
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './shortcut_input.js'; + +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +/** + * @fileoverview + * 'accessibility-shortcuts-page' is responsible for containing all shortcuts + * related to accessibility. + * TODO(jimmyxgong): Implement this skeleton element. + */ +export class AccessibilityShortcutsPageElement extends PolymerElement { + static get is() { + return 'accessibility-shortcuts-page'; + } + + static get template() { + return html`{__html_template__}`; + } +} + +customElements.define(AccessibilityShortcutsPageElement.is, + AccessibilityShortcutsPageElement); \ No newline at end of file
diff --git a/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.html b/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.html new file mode 100644 index 0000000..05a54cd8 --- /dev/null +++ b/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.html
@@ -0,0 +1,2 @@ +<div>Android</div> +<shortcut-input></shortcut-input> \ No newline at end of file
diff --git a/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.js b/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.js new file mode 100644 index 0000000..c343b63 --- /dev/null +++ b/ash/content/shortcut_customization_ui/resources/android_shortcuts_page.js
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './shortcut_input.js'; + +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +/** + * @fileoverview + * 'android-shortcuts-page' is responsible for containing all shortcuts + * related to Android apps. + * TODO(jimmyxgong): Implement this skeleton element. + */ +export class AndroidShortcutsPageElement extends PolymerElement { + static get is() { + return 'android-shortcuts-page'; + } + + static get template() { + return html`{__html_template__}`; + } +} + +customElements.define(AndroidShortcutsPageElement.is, + AndroidShortcutsPageElement); \ No newline at end of file
diff --git a/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js b/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js index 46ece69..e0ec642d 100644 --- a/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js +++ b/ash/content/shortcut_customization_ui/resources/shortcut_customization_app.js
@@ -5,6 +5,8 @@ import './shortcut_input.js'; import './browser_shortcuts_page.js' import './chromeos_shortcuts_page.js' +import './android_shortcuts_page.js' +import './accessibility_shortcuts_page.js' import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import 'chrome://resources/ash/common/navigation_view_panel.js'; @@ -28,6 +30,9 @@ this.$.navigationPanel.addSelector('Chrome OS', 'chromeos-shortcuts-page'); this.$.navigationPanel.addSelector('Browser', 'browser-shortcuts-page'); + this.$.navigationPanel.addSelector('Android', 'android-shortcuts-page'); + this.$.navigationPanel.addSelector('Accessibility', + 'accessibility-shortcuts-page'); } }
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc index 21fe534..026d74b5 100644 --- a/ash/projector/projector_controller_impl.cc +++ b/ash/projector/projector_controller_impl.cc
@@ -56,10 +56,16 @@ void ProjectorControllerImpl::SetProjectorToolsVisible(bool is_visible) { // TODO(yilkal): Projector toolbar shouldn't be shown if soda is not // available. - if (is_visible) + if (is_visible) { ui_controller_->ShowToolbar(); - else - ui_controller_->CloseToolbar(); + OnRecordingStarted(); + return; + } + + OnRecordingEnded(); + if (client_->IsSelfieCamVisible()) + client_->CloseSelfieCam(); + ui_controller_->CloseToolbar(); } bool ProjectorControllerImpl::IsEligible() const { @@ -98,20 +104,6 @@ metadata_controller_->SaveMetadata(saved_video_path); } -void ProjectorControllerImpl::OnRecordButtonPressed() { - // TODO(crbug.com/1165435): Start the recording session and update the button - // visibility based on recording state after integrating with capture mode and - // recording service. - OnRecordingStarted(); -} - -void ProjectorControllerImpl::OnStopRecordButtonPressed() { - // TODO(crbug.com/1165435): Stop the recording session and update the button - // visibility based on recording state after integrating with capture mode and - // recording service. - OnRecordingEnded(); -} - void ProjectorControllerImpl::OnLaserPointerPressed() { ui_controller_->OnLaserPointerPressed(); } @@ -126,6 +118,16 @@ void ProjectorControllerImpl::OnSelfieCamPressed(bool enabled) { ui_controller_->OnSelfieCamPressed(enabled); + + DCHECK_NE(client_, nullptr); + if (enabled == client_->IsSelfieCamVisible()) + return; + + if (enabled) { + client_->ShowSelfieCam(); + return; + } + client_->CloseSelfieCam(); } void ProjectorControllerImpl::OnMagnifierButtonPressed(bool enabled) {
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h index f5faa96..2f9376e 100644 --- a/ash/projector/projector_controller_impl.h +++ b/ash/projector/projector_controller_impl.h
@@ -61,10 +61,6 @@ // Saves the screencast including metadata. void SaveScreencast(const base::FilePath& saved_video_path); - // Invoked when record button is pressed. - void OnRecordButtonPressed(); - void OnStopRecordButtonPressed(); - // Invoked when laser pointer button is pressed. void OnLaserPointerPressed(); // Invoked when marker button is pressed.
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc index 89a68a3b..7370595 100644 --- a/ash/projector/projector_controller_unittest.cc +++ b/ash/projector/projector_controller_unittest.cc
@@ -9,6 +9,7 @@ #include <vector> #include "ash/constants/ash_features.h" +#include "ash/projector/test/mock_projector_client.h" #include "ash/projector/test/mock_projector_metadata_controller.h" #include "ash/projector/test/mock_projector_ui_controller.h" #include "ash/test/ash_test_base.h" @@ -84,12 +85,16 @@ mock_metadata_controller_ = mock_metadata_controller.get(); controller_->SetProjectorMetadataControllerForTest( std::move(mock_metadata_controller)); + + controller_->SetClient(&mock_client_); + controller_->OnSpeechRecognitionAvailable(/*available=*/true); } protected: MockProjectorUiController* mock_ui_controller_ = nullptr; MockProjectorMetadataController* mock_metadata_controller_ = nullptr; ProjectorControllerImpl* controller_; + MockProjectorClient mock_client_; private: base::test::ScopedFeatureList scoped_feature_list_; @@ -101,6 +106,15 @@ controller_->SetProjectorToolsVisible(true); } +TEST_F(ProjectorControllerTest, CloseToolbar) { + controller_->SetProjectorToolsVisible(/*is_visible=*/true); + mock_client_.SetSelfieCamVisible(/*visible=*/true); + // Verify that |CloseToolbar| in |ProjectorUiController| is called. + EXPECT_CALL(*mock_ui_controller_, CloseToolbar()).Times(1); + EXPECT_CALL(mock_client_, CloseSelfieCam()).Times(1); + controller_->SetProjectorToolsVisible(/*is_visible=*/false); +} + TEST_F(ProjectorControllerTest, SaveScreencast) { base::FilePath saved_path; // Verify that |SaveMetadata| in |ProjectorMetadataController| is called. @@ -200,11 +214,15 @@ TEST_F(ProjectorControllerTest, OnSelfieCamPressed) { // Verify that |OnSelfieCamPressed| in |ProjectorUiController| is called. - EXPECT_CALL(*mock_ui_controller_, OnSelfieCamPressed(true)); - controller_->OnSelfieCamPressed(true); + EXPECT_CALL(*mock_ui_controller_, OnSelfieCamPressed(/*enabled=*/true)); + EXPECT_CALL(mock_client_, ShowSelfieCam()); + controller_->OnSelfieCamPressed(/*enabled=*/true); + mock_client_.SetSelfieCamVisible(/*visible=*/true); - EXPECT_CALL(*mock_ui_controller_, OnSelfieCamPressed(false)); - controller_->OnSelfieCamPressed(false); + EXPECT_CALL(*mock_ui_controller_, OnSelfieCamPressed(/*enabled=*/false)); + EXPECT_CALL(mock_client_, CloseSelfieCam()); + controller_->OnSelfieCamPressed(/*enabled=*/false); + mock_client_.SetSelfieCamVisible(/*visible=*/false); } TEST_F(ProjectorControllerTest, SetCaptionBubbleState) { @@ -222,4 +240,20 @@ controller_->OnChangeMarkerColorPressed(SK_ColorBLACK); } +TEST_F(ProjectorControllerTest, RecordingStarted) { + EXPECT_CALL(mock_client_, StartSpeechRecognition()); + EXPECT_CALL(*mock_ui_controller_, OnRecordingStateChanged(/*started=*/true)); + EXPECT_CALL(*mock_metadata_controller_, OnRecordingStarted()); + controller_->OnRecordingStarted(); +} + +TEST_F(ProjectorControllerTest, RecordingEnded) { + controller_->OnRecordingStarted(); + mock_client_.SetSelfieCamVisible(/*visible=*/true); + EXPECT_CALL(mock_client_, StopSpeechRecognition()); + EXPECT_CALL(*mock_ui_controller_, OnRecordingStateChanged(/*started=*/false)); + EXPECT_CALL(mock_client_, CloseSelfieCam()); + controller_->SetProjectorToolsVisible(/*is_visible=*/false); +} + } // namespace ash
diff --git a/ash/projector/projector_ui_controller.cc b/ash/projector/projector_ui_controller.cc index 51a6de1..6db267d2 100644 --- a/ash/projector/projector_ui_controller.cc +++ b/ash/projector/projector_ui_controller.cc
@@ -233,12 +233,11 @@ } void ProjectorUiController::OnSelfieCamPressed(bool enabled) { - // TODO(crbug/1199396): If enabled, launch the web UI. - // If the selfie cam is visible, then the button for turning on the selfie cam // should be hidden in the projector bar view. The button for turning off the // selfie cam should show instead. - projector_bar_view_->OnSelfieCamStateChanged(enabled); + if (projector_bar_view_) + projector_bar_view_->OnSelfieCamStateChanged(enabled); } void ProjectorUiController::OnRecordingStateChanged(bool started) {
diff --git a/ash/projector/projector_ui_controller_unittest.cc b/ash/projector/projector_ui_controller_unittest.cc index c857625e..e6ccb54 100644 --- a/ash/projector/projector_ui_controller_unittest.cc +++ b/ash/projector/projector_ui_controller_unittest.cc
@@ -180,16 +180,13 @@ TEST_F(ProjectorUiControllerTest, RecordingState) { controller_->ShowToolbar(); ProjectorBarView* bar_view_ = controller_->projector_bar_view(); - EXPECT_TRUE(bar_view_->IsRecordButtonVisible()); EXPECT_FALSE(bar_view_->IsKeyIdeaButtonEnabled()); controller_->OnRecordingStateChanged(/* started = */ true); - EXPECT_FALSE(bar_view_->IsRecordButtonVisible()); EXPECT_TRUE(bar_view_->IsKeyIdeaButtonEnabled()); EXPECT_TRUE(bar_view_->IsClosedCaptionEnabled()); controller_->OnRecordingStateChanged(/* started = */ false); - EXPECT_TRUE(bar_view_->IsRecordButtonVisible()); EXPECT_FALSE(bar_view_->IsKeyIdeaButtonEnabled()); EXPECT_FALSE(bar_view_->IsClosedCaptionEnabled()); }
diff --git a/ash/projector/test/mock_projector_client.cc b/ash/projector/test/mock_projector_client.cc new file mode 100644 index 0000000..3745f249 --- /dev/null +++ b/ash/projector/test/mock_projector_client.cc
@@ -0,0 +1,20 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/projector/test/mock_projector_client.h" + +namespace ash { + +MockProjectorClient::MockProjectorClient() = default; +MockProjectorClient::~MockProjectorClient() = default; + +bool MockProjectorClient::IsSelfieCamVisible() const { + return is_selfie_cam_visible_; +} + +void MockProjectorClient::SetSelfieCamVisible(bool visible) { + is_selfie_cam_visible_ = visible; +} + +} // namespace ash
diff --git a/ash/projector/test/mock_projector_client.h b/ash/projector/test/mock_projector_client.h new file mode 100644 index 0000000..d236104d --- /dev/null +++ b/ash/projector/test/mock_projector_client.h
@@ -0,0 +1,37 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_PROJECTOR_TEST_MOCK_PROJECTOR_CLIENT_H_ +#define ASH_PROJECTOR_TEST_MOCK_PROJECTOR_CLIENT_H_ + +#include "ash/ash_export.h" +#include "ash/public/cpp/projector/projector_client.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace ash { + +// A mock implementation of ProjectorClient for use in tests. +class ASH_EXPORT MockProjectorClient : public ProjectorClient { + public: + MockProjectorClient(); + MockProjectorClient(const MockProjectorClient&) = delete; + MockProjectorClient& operator=(const MockProjectorClient&) = delete; + virtual ~MockProjectorClient(); + + // ProjectorClient: + MOCK_METHOD0(StartSpeechRecognition, void()); + MOCK_METHOD0(StopSpeechRecognition, void()); + MOCK_METHOD0(ShowSelfieCam, void()); + MOCK_METHOD0(CloseSelfieCam, void()); + + bool IsSelfieCamVisible() const override; + void SetSelfieCamVisible(bool visible); + + private: + bool is_selfie_cam_visible_ = false; +}; + +} // namespace ash + +#endif // ASH_PROJECTOR_TEST_MOCK_PROJECTOR_CLIENT_H_
diff --git a/ash/projector/test/mock_projector_ui_controller.cc b/ash/projector/test/mock_projector_ui_controller.cc index 04d332f..d2930a22 100644 --- a/ash/projector/test/mock_projector_ui_controller.cc +++ b/ash/projector/test/mock_projector_ui_controller.cc
@@ -1,5 +1,4 @@ // Copyright 2021 The Chromium Authors. All rights reserved. -// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/ash/projector/test/mock_projector_ui_controller.h b/ash/projector/test/mock_projector_ui_controller.h index 05c8440..5992c76 100644 --- a/ash/projector/test/mock_projector_ui_controller.h +++ b/ash/projector/test/mock_projector_ui_controller.h
@@ -5,6 +5,7 @@ #ifndef ASH_PROJECTOR_TEST_MOCK_PROJECTOR_UI_CONTROLLER_H_ #define ASH_PROJECTOR_TEST_MOCK_PROJECTOR_UI_CONTROLLER_H_ +#include "ash/ash_export.h" #include "ash/projector/projector_ui_controller.h" #include "testing/gmock/include/gmock/gmock.h" @@ -26,6 +27,7 @@ // ProjectorUiController: MOCK_METHOD0(ShowToolbar, void()); + MOCK_METHOD0(CloseToolbar, void()); MOCK_METHOD0(OnKeyIdeaMarked, void()); MOCK_METHOD0(OnLaserPointerPressed, void()); MOCK_METHOD0(OnMarkerPressed, void());
diff --git a/ash/projector/ui/projector_bar_view.cc b/ash/projector/ui/projector_bar_view.cc index 26dde39..b064484 100644 --- a/ash/projector/ui/projector_bar_view.cc +++ b/ash/projector/ui/projector_bar_view.cc
@@ -7,9 +7,12 @@ #include "ash/projector/projector_controller_impl.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" #include "ash/wm/work_area_insets.h" #include "components/vector_icons/vector_icons.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/background.h" @@ -37,11 +40,6 @@ // |ProjectorBarView|. constexpr int kBetweenChildSpacing = 16; -// Recording buttons. -constexpr int kRecordingButtonColorViewSize = 12; -constexpr int kStartRecordingButtonColorViewRadius = 6; -constexpr int kStopRecordingButtonColorViewRadius = 2; - // Color selection buttons. constexpr int kColorButtonColorViewSize = 24; constexpr int kColorButtonViewRadius = 12; @@ -52,6 +50,23 @@ constexpr SkColor kProjectorColors[] = {SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLUE}; +std::u16string GetColorName(SkColor color) { + int name = IDS_UNKNOWN_COLOR_BUTTON; + switch (color) { + case SK_ColorBLACK: + name = IDS_BLACK_COLOR_BUTTON; + break; + case SK_ColorWHITE: + name = IDS_WHITE_COLOR_BUTTON; + break; + case SK_ColorBLUE: + name = IDS_BLUE_COLOR_BUTTON; + break; + } + DCHECK_NE(name, IDS_UNKNOWN_COLOR_BUTTON); + return l10n_util::GetStringUTF16(name); +} + } // namespace // static @@ -87,9 +102,6 @@ } void ProjectorBarView::OnRecordingStateChanged(bool started) { - record_button_->SetVisible(!started); - stop_button_->SetVisible(started); - // Closed caption and key idea buttons states are dependent on the recording // state. auto recording_related_buttons_state = @@ -143,10 +155,6 @@ views::View::OnThemeChanged(); } -bool ProjectorBarView::IsRecordButtonVisible() const { - return record_button_->GetVisible(); -} - bool ProjectorBarView::IsKeyIdeaButtonEnabled() const { return key_idea_button_->GetState() == views::Button::ButtonState::STATE_NORMAL; @@ -175,24 +183,11 @@ views::Painter::CreateSolidRoundRectPainter( SkColorSetA(gfx::kGoogleGrey900, kBarAlpha_), kBarRadius))); - // Add recording buttons. - record_button_ = AddChildView(std::make_unique<ProjectorColorButton>( - base::BindRepeating(&ProjectorBarView::OnRecordButtonPressed, - base::Unretained(this)), - SK_ColorWHITE, kRecordingButtonColorViewSize, - kStartRecordingButtonColorViewRadius)); - stop_button_ = AddChildView(std::make_unique<ProjectorColorButton>( - base::BindRepeating(&ProjectorBarView::OnStopButtonPressed, - base::Unretained(this)), - SK_ColorRED, kRecordingButtonColorViewSize, - kStopRecordingButtonColorViewRadius)), - stop_button_->SetVisible(false); - // Add key idea button. key_idea_button_ = AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnKeyIdeaButtonPressed, base::Unretained(this)), - kProjectorKeyIdeaIcon)); + kProjectorKeyIdeaIcon, l10n_util::GetStringUTF16(IDS_KEY_IDEA_BUTTON))); key_idea_button_->SetState(views::Button::ButtonState::STATE_DISABLED); // Add separator view @@ -202,13 +197,14 @@ laser_pointer_button_ = AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnLaserPointerPressed, base::Unretained(this)), - kPaletteTrayIconLaserPointerIcon)); + kPaletteTrayIconLaserPointerIcon, + l10n_util::GetStringUTF16(IDS_LASER_POINTER_BUTTON))); // Add marker button. marker_button_ = AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnMarkerPressed, base::Unretained(this)), - kProjectorMarkerIcon)); + kProjectorMarkerIcon, l10n_util::GetStringUTF16(IDS_MARKER_BUTTON))); CreateMarkerOptionsBar(); @@ -238,33 +234,37 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnInkPenButtonPressed, base::Unretained(this)), - kInkPenIcon)); + kInkPenIcon, l10n_util::GetStringUTF16(IDS_INK_PEN_BUTTON))); marker_pen_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnMarkerPenButtonPressed, base::Unretained(this)), - kMarkerIcon)); + kMarkerIcon, l10n_util::GetStringUTF16(IDS_MARKER_PEN_BUTTON))); for (const auto& color : kProjectorColors) { + std::u16string button_name = l10n_util::GetStringFUTF16( + IDS_MARKER_COLOR_BUTTON, GetColorName(color)); marker_color_buttons_.push_back( box_layout->AddChildView(std::make_unique<ProjectorColorButton>( base::BindRepeating(&ProjectorBarView::OnChangeMarkerColorPressed, base::Unretained(this), color), - color, kColorButtonColorViewSize, kColorButtonViewRadius))); + color, kColorButtonColorViewSize, kColorButtonViewRadius, + button_name))); } undo_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnUndoButtonPressed, base::Unretained(this)), - kUndoIcon)); + kUndoIcon, l10n_util::GetStringUTF16(IDS_UNDO_BUTTON))); // Add clear all markers button. clear_all_markers_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnClearAllMarkersPressed, base::Unretained(this)), - kTrashCanIcon)); + kTrashCanIcon, + l10n_util::GetStringUTF16(IDS_CLEAR_ALL_MARKERS_BUTTON))); // This button is disabled by default until marker mode activated. clear_all_markers_button_->SetEnabled(marker_button_->GetToggled()); @@ -273,11 +273,13 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnCaretButtonPressed, base::Unretained(this), /* expand =*/true), - kCaretRightIcon)); + kCaretRightIcon, + l10n_util::GetStringUTF16(IDS_EXPAND_MARKER_TOOLS_BUTTON))); caret_left_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnCaretButtonPressed, base::Unretained(this), /* expand =*/false), - kCaretLeftIcon)); + kCaretLeftIcon, + l10n_util::GetStringUTF16(IDS_COLLAPSE_MARKER_TOOLS_BUTTON))); marker_bar_ = AddChildView(std::move(box_layout)); marker_bar_->SetVisible(false); @@ -295,13 +297,13 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnMagnifierButtonPressed, base::Unretained(this), /* enabled =*/true), - kZoomInIcon)); + kZoomInIcon, l10n_util::GetStringUTF16(IDS_START_MAGNIFIER_BUTTON))); magnifier_start_button_->SetVisible(true); magnifier_stop_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnMagnifierButtonPressed, base::Unretained(this), /* enabled =*/false), - kZoomOutIcon)); + kZoomOutIcon, l10n_util::GetStringUTF16(IDS_STOP_MAGNIFIER_BUTTON))); magnifier_stop_button_->SetVisible(false); AddSeparatorViewToView(box_layout.get()); @@ -311,14 +313,16 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnSelfieCamPressed, base::Unretained(this), /*enabled=*/true), - kProjectorSelfieCamOnIcon)); + kProjectorSelfieCamOnIcon, + l10n_util::GetStringUTF16(IDS_START_SELFIE_CAMERA_BUTTON))); selfie_cam_on_button_->SetVisible(true); selfie_cam_off_button_ = box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::OnSelfieCamPressed, base::Unretained(this), /*enabled=*/false), - kProjectorSelfieCamOffIcon)); + kProjectorSelfieCamOffIcon, + l10n_util::GetStringUTF16(IDS_STOP_SELFIE_CAMERA_BUTTON))); selfie_cam_off_button_->SetVisible(false); // Add closed caption show/hide buttons. @@ -326,7 +330,8 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::SetCaptionState, base::Unretained(this), false), - kHideClosedCaptionIcon)); + kHideClosedCaptionIcon, + l10n_util::GetStringUTF16(IDS_STOP_CLOSED_CAPTIONS_BUTTON))); closed_caption_hide_button_->SetVisible(false); closed_caption_hide_button_->SetState( views::Button::ButtonState::STATE_DISABLED); @@ -335,7 +340,8 @@ box_layout->AddChildView(std::make_unique<ProjectorImageButton>( base::BindRepeating(&ProjectorBarView::SetCaptionState, base::Unretained(this), true), - kShowClosedCaptionIcon)); + kShowClosedCaptionIcon, + l10n_util::GetStringUTF16(IDS_START_CLOSED_CAPTIONS_BUTTON))); closed_caption_show_button_->SetVisible(true); closed_caption_show_button_->SetState( views::Button::ButtonState::STATE_DISABLED); @@ -347,19 +353,12 @@ base::BindRepeating( &ProjectorBarView::OnChangeBarLocationButtonPressed, base::Unretained(this)), - kAutoclickPositionBottomLeftIcon)); + kAutoclickPositionBottomLeftIcon, + l10n_util::GetStringUTF16(IDS_BAR_LOCATION_BUTTON))); bar_location_button_->SetVisible(true); tools_bar_ = AddChildView(std::move(box_layout)); } -void ProjectorBarView::OnRecordButtonPressed() { - projector_controller_->OnRecordButtonPressed(); -} - -void ProjectorBarView::OnStopButtonPressed() { - projector_controller_->OnStopRecordButtonPressed(); -} - void ProjectorBarView::OnKeyIdeaButtonPressed() { DCHECK(projector_controller_); projector_controller_->MarkKeyIdea(); @@ -403,7 +402,7 @@ bar_location_ = BarLocation::kUpperLeft; bar_location_button_->SetVectorIcon(kAutoclickPositionTopLeftIcon); break; - }; + } GetWidget()->SetBounds(CalculateBoundsInScreen()); }
diff --git a/ash/projector/ui/projector_bar_view.h b/ash/projector/ui/projector_bar_view.h index 564c708..9fb44e0 100644 --- a/ash/projector/ui/projector_bar_view.h +++ b/ash/projector/ui/projector_bar_view.h
@@ -53,7 +53,6 @@ // views::View: void OnThemeChanged() override; - bool IsRecordButtonVisible() const; bool IsKeyIdeaButtonEnabled() const; bool IsClosedCaptionEnabled() const; @@ -72,8 +71,6 @@ void CreateMarkerOptionsBar(); void CreateTrailingButtonsBar(); - void OnRecordButtonPressed(); - void OnStopButtonPressed(); void OnKeyIdeaButtonPressed(); void OnLaserPointerPressed(); void OnMarkerPressed(); @@ -91,8 +88,6 @@ void UpdateToolbarButtonsVisibility(); gfx::Rect CalculateBoundsInScreen() const; - ProjectorColorButton* record_button_ = nullptr; - ProjectorColorButton* stop_button_ = nullptr; ProjectorButton* key_idea_button_ = nullptr; ProjectorButton* laser_pointer_button_ = nullptr; ProjectorButton* marker_button_ = nullptr;
diff --git a/ash/projector/ui/projector_button.cc b/ash/projector/ui/projector_button.cc index 36d3ce2..c0d123b 100644 --- a/ash/projector/ui/projector_button.cc +++ b/ash/projector/ui/projector_button.cc
@@ -21,8 +21,9 @@ } // namespace -ProjectorButton::ProjectorButton(views::Button::PressedCallback callback) - : ToggleImageButton(callback) { +ProjectorButton::ProjectorButton(views::Button::PressedCallback callback, + const std::u16string& name) + : ToggleImageButton(callback), name_(name) { SetPreferredSize({kProjectorButtonSize, kProjectorButtonSize}); SetBorder(views::CreateEmptyBorder(kButtonPadding)); @@ -61,4 +62,9 @@ ink_drop()->SetHighlightOpacity(ripple_attributes.highlight_opacity); } +void ProjectorButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ax::mojom::Role::kButton; + node_data->SetName(name_); +} + } // namespace ash
diff --git a/ash/projector/ui/projector_button.h b/ash/projector/ui/projector_button.h index bab80be..71256554 100644 --- a/ash/projector/ui/projector_button.h +++ b/ash/projector/ui/projector_button.h
@@ -5,6 +5,8 @@ #ifndef ASH_PROJECTOR_UI_PROJECTOR_BUTTON_H_ #define ASH_PROJECTOR_UI_PROJECTOR_BUTTON_H_ +#include <string> + #include "ash/ash_export.h" #include "ui/views/controls/button/image_button.h" @@ -17,7 +19,8 @@ public: const int kProjectorButtonSize = 32; - explicit ProjectorButton(views::Button::PressedCallback callback); + ProjectorButton(views::Button::PressedCallback callback, + const std::u16string& name); ProjectorButton(const ProjectorButton&) = delete; ProjectorButton& operator=(const ProjectorButton&) = delete; ~ProjectorButton() override = default; @@ -25,6 +28,10 @@ // views::ToggleImageButton: void OnPaintBackground(gfx::Canvas* canvas) override; void OnThemeChanged() override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + private: + std::u16string name_; }; } // namespace ash
diff --git a/ash/projector/ui/projector_color_button.cc b/ash/projector/ui/projector_color_button.cc index 47276ef..2f4d3d3 100644 --- a/ash/projector/ui/projector_color_button.cc +++ b/ash/projector/ui/projector_color_button.cc
@@ -14,8 +14,9 @@ views::Button::PressedCallback callback, SkColor color, int size, - float radius) - : ProjectorButton(callback) { + float radius, + const std::u16string& name) + : ProjectorButton(callback, name) { // Add the color view. auto* color_view = AddChildView(std::make_unique<View>()); color_view->SetBounds((kProjectorButtonSize - size) / 2,
diff --git a/ash/projector/ui/projector_color_button.h b/ash/projector/ui/projector_color_button.h index f51d325..dc03fba 100644 --- a/ash/projector/ui/projector_color_button.h +++ b/ash/projector/ui/projector_color_button.h
@@ -5,6 +5,8 @@ #ifndef ASH_PROJECTOR_UI_PROJECTOR_COLOR_BUTTON_H_ #define ASH_PROJECTOR_UI_PROJECTOR_COLOR_BUTTON_H_ +#include <string> + #include "ash/ash_export.h" #include "ash/projector/ui/projector_button.h" @@ -17,7 +19,8 @@ ProjectorColorButton(views::Button::PressedCallback callback, SkColor color, int size, - float radius); + float radius, + const std::u16string& name); ProjectorColorButton(const ProjectorColorButton&) = delete; ProjectorColorButton& operator=(const ProjectorColorButton&) = delete; ~ProjectorColorButton() override = default;
diff --git a/ash/projector/ui/projector_image_button.cc b/ash/projector/ui/projector_image_button.cc index e4ab674..1363f55b 100644 --- a/ash/projector/ui/projector_image_button.cc +++ b/ash/projector/ui/projector_image_button.cc
@@ -13,8 +13,9 @@ ProjectorImageButton::ProjectorImageButton( views::Button::PressedCallback callback, - const gfx::VectorIcon& icon) - : ProjectorButton(callback) { + const gfx::VectorIcon& icon, + const std::u16string& name) + : ProjectorButton(callback, name) { SetVectorIcon(icon); }
diff --git a/ash/projector/ui/projector_image_button.h b/ash/projector/ui/projector_image_button.h index 1c99777..71bca31 100644 --- a/ash/projector/ui/projector_image_button.h +++ b/ash/projector/ui/projector_image_button.h
@@ -5,6 +5,8 @@ #ifndef ASH_PROJECTOR_UI_PROJECTOR_IMAGE_BUTTON_H_ #define ASH_PROJECTOR_UI_PROJECTOR_IMAGE_BUTTON_H_ +#include <string> + #include "ash/ash_export.h" #include "ash/projector/ui/projector_button.h" @@ -19,7 +21,8 @@ class ASH_EXPORT ProjectorImageButton : public ProjectorButton { public: ProjectorImageButton(views::Button::PressedCallback callback, - const gfx::VectorIcon& icon); + const gfx::VectorIcon& icon, + const std::u16string& name); ProjectorImageButton(const ProjectorImageButton&) = delete; ProjectorImageButton& operator=(const ProjectorImageButton&) = delete; ~ProjectorImageButton() override = default;
diff --git a/ash/public/cpp/OWNERS b/ash/public/cpp/OWNERS index f3c487d..ea1744a 100644 --- a/ash/public/cpp/OWNERS +++ b/ash/public/cpp/OWNERS
@@ -1,2 +1,3 @@ per-file *login*=file://ash/login/OWNERS per-file *shelf*=file://ash/shelf/OWNERS +per-file *wallpaper*=file://ash/wallpaper/OWNERS
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc index c6f062c..7cdcff0 100644 --- a/ash/public/cpp/app_list/app_list_features.cc +++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -52,7 +52,7 @@ const base::Feature kCategoricalSearch{"CategoricalSearch", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kLauncherQueryHighlighting{ - "LauncherQueryHighlighting", base::FEATURE_DISABLED_BY_DEFAULT}; + "LauncherQueryHighlighting", base::FEATURE_ENABLED_BY_DEFAULT}; bool IsAppDataSearchEnabled() { return base::FeatureList::IsEnabled(kEnableAppDataSearch);
diff --git a/ash/public/cpp/projector/projector_client.h b/ash/public/cpp/projector/projector_client.h index 317d1b7..b96609c 100644 --- a/ash/public/cpp/projector/projector_client.h +++ b/ash/public/cpp/projector/projector_client.h
@@ -20,6 +20,12 @@ virtual void StartSpeechRecognition() = 0; virtual void StopSpeechRecognition() = 0; + + // TODO(crbug/1199396): Migrate to IPC after Lacros launch and ash-chrome + // deprecation. + virtual void ShowSelfieCam() = 0; + virtual void CloseSelfieCam() = 0; + virtual bool IsSelfieCamVisible() const = 0; }; } // namespace ash
diff --git a/ash/system/accessibility/floating_accessibility_view.cc b/ash/system/accessibility/floating_accessibility_view.cc index aadd4c5b..575ab620 100644 --- a/ash/system/accessibility/floating_accessibility_view.cc +++ b/ash/system/accessibility/floating_accessibility_view.cc
@@ -15,7 +15,7 @@ #include "ash/style/ash_color_provider.h" #include "ash/system/accessibility/dictation_button_tray.h" #include "ash/system/accessibility/floating_menu_button.h" -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/virtual_keyboard/virtual_keyboard_tray.h" #include "base/bind.h"
diff --git a/ash/system/accessibility/select_to_speak_constants.h b/ash/system/accessibility/select_to_speak/select_to_speak_constants.h similarity index 82% rename from ash/system/accessibility/select_to_speak_constants.h rename to ash/system/accessibility/select_to_speak/select_to_speak_constants.h index 8265fc2..4e0c775 100644 --- a/ash/system/accessibility/select_to_speak_constants.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_constants.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_CONSTANTS_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_CONSTANTS_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_CONSTANTS_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_CONSTANTS_H_ namespace ash { @@ -28,4 +28,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_CONSTANTS_H_ \ No newline at end of file +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_CONSTANTS_H_
diff --git a/ash/system/accessibility/select_to_speak_menu_bubble_controller.cc b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.cc similarity index 96% rename from ash/system/accessibility/select_to_speak_menu_bubble_controller.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.cc index a9fc72a0b..1085727 100644 --- a/ash/system/accessibility/select_to_speak_menu_bubble_controller.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_menu_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/accessibility/floating_menu_utils.h" -#include "ash/system/accessibility/select_to_speak_constants.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_constants.h" #include "ash/system/tray/tray_background_view.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/unified/unified_system_tray_view.h"
diff --git a/ash/system/accessibility/select_to_speak_menu_bubble_controller.h b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h similarity index 80% rename from ash/system/accessibility/select_to_speak_menu_bubble_controller.h rename to ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h index 1966cb25..4d24733 100644 --- a/ash/system/accessibility/select_to_speak_menu_bubble_controller.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_ #include "ash/ash_export.h" #include "ash/public/cpp/accessibility_controller_enums.h" -#include "ash/system/accessibility/select_to_speak_menu_view.h" -#include "ash/system/accessibility/select_to_speak_speed_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h" #include "ash/system/tray/tray_bubble_view.h" #include "ui/wm/public/activation_change_observer.h" @@ -62,4 +62,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_BUBBLE_CONTROLLER_H_
diff --git a/ash/system/accessibility/select_to_speak_menu_bubble_controller_unittest.cc b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller_unittest.cc similarity index 97% rename from ash/system/accessibility/select_to_speak_menu_bubble_controller_unittest.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller_unittest.cc index 7f23a32..b804802a 100644 --- a/ash/system/accessibility/select_to_speak_menu_bubble_controller_unittest.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_menu_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/accessibility/test_accessibility_controller_client.h" @@ -10,7 +10,7 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/accessibility/floating_menu_button.h" -#include "ash/system/accessibility/select_to_speak_menu_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" #include "ui/accessibility/accessibility_features.h" @@ -274,4 +274,4 @@ !GetSpeedBubbleController()->IsVisible()); } -} // namespace ash \ No newline at end of file +} // namespace ash
diff --git a/ash/system/accessibility/select_to_speak_menu_view.cc b/ash/system/accessibility/select_to_speak/select_to_speak_menu_view.cc similarity index 97% rename from ash/system/accessibility/select_to_speak_menu_view.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_menu_view.cc index 9089141..37d91f9 100644 --- a/ash/system/accessibility/select_to_speak_menu_view.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_menu_view.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_menu_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h" #include "ash/public/cpp/accessibility_controller_enums.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" #include "ash/system/accessibility/floating_menu_button.h" -#include "ash/system/accessibility/select_to_speak_constants.h" -#include "ash/system/accessibility/select_to_speak_metrics_utils.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_constants.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_metrics_utils.h" #include "ash/system/tray/tray_constants.h" #include "base/bind.h" #include "base/i18n/rtl.h"
diff --git a/ash/system/accessibility/select_to_speak_menu_view.h b/ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h similarity index 91% rename from ash/system/accessibility/select_to_speak_menu_view.h rename to ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h index 8d6a1d6e..0044369 100644 --- a/ash/system/accessibility/select_to_speak_menu_view.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_VIEW_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_VIEW_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_VIEW_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_VIEW_H_ #include "ash/ash_export.h" #include "ash/public/cpp/accessibility_controller_enums.h" @@ -88,4 +88,4 @@ DEFINE_VIEW_BUILDER(/* no export */, ash::SelectToSpeakMenuView) -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_MENU_VIEW_H_ \ No newline at end of file +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_MENU_VIEW_H_
diff --git a/ash/system/accessibility/select_to_speak_metrics_utils.h b/ash/system/accessibility/select_to_speak/select_to_speak_metrics_utils.h similarity index 76% rename from ash/system/accessibility/select_to_speak_metrics_utils.h rename to ash/system/accessibility/select_to_speak/select_to_speak_metrics_utils.h index ed33bee..460fe413 100644 --- a/ash/system/accessibility/select_to_speak_metrics_utils.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_metrics_utils.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_METRICS_UTILS_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_METRICS_UTILS_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_METRICS_UTILS_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_METRICS_UTILS_H_ namespace ash { @@ -23,4 +23,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_METRICS_UTILS_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_METRICS_UTILS_H_
diff --git a/ash/system/accessibility/select_to_speak_speed_bubble_controller.cc b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.cc similarity index 93% rename from ash/system/accessibility/select_to_speak_speed_bubble_controller.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.cc index cbe045c3..2ec2262 100644 --- a/ash/system/accessibility/select_to_speak_speed_bubble_controller.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_speed_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/public/cpp/accessibility_controller_enums.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/system/accessibility/floating_menu_utils.h" -#include "ash/system/accessibility/select_to_speak_constants.h" -#include "ash/system/accessibility/select_to_speak_speed_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_constants.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h" #include "ash/system/tray/tray_background_view.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/unified/unified_system_tray_view.h"
diff --git a/ash/system/accessibility/select_to_speak_speed_bubble_controller.h b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h similarity index 84% rename from ash/system/accessibility/select_to_speak_speed_bubble_controller.h rename to ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h index f0ecc46..681ea356 100644 --- a/ash/system/accessibility/select_to_speak_speed_bubble_controller.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_ #include "ash/ash_export.h" -#include "ash/system/accessibility/select_to_speak_speed_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h" #include "ash/system/tray/tray_bubble_view.h" #include "ash/system/tray/view_click_listener.h" #include "ui/wm/public/activation_change_observer.h" @@ -61,4 +61,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_BUBBLE_CONTROLLER_H_
diff --git a/ash/system/accessibility/select_to_speak_speed_bubble_controller_unittest.cc b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller_unittest.cc similarity index 94% rename from ash/system/accessibility/select_to_speak_speed_bubble_controller_unittest.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller_unittest.cc index 0677a44e..871acc2d 100644 --- a/ash/system/accessibility/select_to_speak_speed_bubble_controller_unittest.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_speed_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/accessibility/test_accessibility_controller_client.h" @@ -10,9 +10,9 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/accessibility/floating_menu_button.h" -#include "ash/system/accessibility/select_to_speak_menu_bubble_controller.h" -#include "ash/system/accessibility/select_to_speak_menu_view.h" -#include "ash/system/accessibility/select_to_speak_speed_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" @@ -173,4 +173,4 @@ EXPECT_TRUE(speed_button->HasFocus()); } -} // namespace ash \ No newline at end of file +} // namespace ash
diff --git a/ash/system/accessibility/select_to_speak_speed_view.cc b/ash/system/accessibility/select_to_speak/select_to_speak_speed_view.cc similarity index 94% rename from ash/system/accessibility/select_to_speak_speed_view.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_speed_view.cc index 8e87701..d3fcf02c 100644 --- a/ash/system/accessibility/select_to_speak_speed_view.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_speed_view.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_speed_view.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" -#include "ash/system/accessibility/select_to_speak_constants.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_constants.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/system/tray/tray_popup_utils.h" #include "base/bind.h"
diff --git a/ash/system/accessibility/select_to_speak_speed_view.h b/ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h similarity index 88% rename from ash/system/accessibility/select_to_speak_speed_view.h rename to ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h index 376b836e..9dc13b1 100644 --- a/ash/system/accessibility/select_to_speak_speed_view.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_VIEW_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_VIEW_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_VIEW_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_VIEW_H_ #include "ash/ash_export.h" #include "ash/system/tray/view_click_listener.h" @@ -64,4 +64,4 @@ DEFINE_VIEW_BUILDER(/* no export */, ash::SelectToSpeakSpeedView) -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SPEED_VIEW_H_ \ No newline at end of file +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_SPEED_VIEW_H_
diff --git a/ash/system/accessibility/select_to_speak_tray.cc b/ash/system/accessibility/select_to_speak/select_to_speak_tray.cc similarity index 97% rename from ash/system/accessibility/select_to_speak_tray.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_tray.cc index fd57751..fb3e0d2 100644 --- a/ash/system/accessibility/select_to_speak_tray.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_tray.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/resources/vector_icons/vector_icons.h" @@ -31,7 +31,6 @@ SelectToSpeakTray::SelectToSpeakTray(Shelf* shelf) : TrayBackgroundView(shelf), icon_(new views::ImageView()) { - UpdateIconsForSession(); icon_->SetImage(inactive_image_); const int vertical_padding = (kTrayItemSize - inactive_image_.height()) / 2;
diff --git a/ash/system/accessibility/select_to_speak_tray.h b/ash/system/accessibility/select_to_speak/select_to_speak_tray.h similarity index 90% rename from ash/system/accessibility/select_to_speak_tray.h rename to ash/system/accessibility/select_to_speak/select_to_speak_tray.h index 69ed5c9..c1bacf5 100644 --- a/ash/system/accessibility/select_to_speak_tray.h +++ b/ash/system/accessibility/select_to_speak/select_to_speak_tray.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_TRAY_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_TRAY_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_TRAY_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_TRAY_H_ #include "ash/accessibility/accessibility_observer.h" #include "ash/ash_export.h" @@ -67,4 +67,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_TRAY_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SELECT_TO_SPEAK_SELECT_TO_SPEAK_TRAY_H_
diff --git a/ash/system/accessibility/select_to_speak_tray_unittest.cc b/ash/system/accessibility/select_to_speak/select_to_speak_tray_unittest.cc similarity index 98% rename from ash/system/accessibility/select_to_speak_tray_unittest.cc rename to ash/system/accessibility/select_to_speak/select_to_speak_tray_unittest.cc index 7fbfdb47..1e869ab 100644 --- a/ash/system/accessibility/select_to_speak_tray_unittest.cc +++ b/ash/system/accessibility/select_to_speak/select_to_speak_tray_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/accelerators/accelerator_controller_impl.h" #include "ash/accessibility/accessibility_controller_impl.h"
diff --git a/ash/system/accessibility/switch_access_back_button_bubble_controller.cc b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.cc similarity index 96% rename from ash/system/accessibility/switch_access_back_button_bubble_controller.cc rename to ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.cc index 571936d..8abb16fcc 100644 --- a/ash/system/accessibility/switch_access_back_button_bubble_controller.cc +++ b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_back_button_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/accessibility/switch_access_back_button_view.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_view.h" #include "ash/system/tray/tray_background_view.h" #include "ash/system/tray/tray_constants.h" #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/ash/system/accessibility/switch_access_back_button_bubble_controller.h b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h similarity index 84% rename from ash/system/accessibility/switch_access_back_button_bubble_controller.h rename to ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h index 77f6599..a303238 100644 --- a/ash/system/accessibility/switch_access_back_button_bubble_controller.h +++ b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_ #include "ash/system/tray/tray_bubble_view.h" @@ -54,4 +54,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_BUBBLE_CONTROLLER_H_
diff --git a/ash/system/accessibility/switch_access_back_button_bubble_controller_unittest.cc b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller_unittest.cc similarity index 91% rename from ash/system/accessibility/switch_access_back_button_bubble_controller_unittest.cc rename to ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller_unittest.cc index 5d9e745..538fc6a 100644 --- a/ash/system/accessibility/switch_access_back_button_bubble_controller_unittest.cc +++ b/ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_back_button_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/shell.h" -#include "ash/system/accessibility/switch_access_back_button_bubble_controller.h" -#include "ash/system/accessibility/switch_access_back_button_view.h" -#include "ash/system/accessibility/switch_access_menu_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_view.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h" #include "ash/test/ash_test_base.h" #include "ui/display/display.h" #include "ui/display/screen.h"
diff --git a/ash/system/accessibility/switch_access_back_button_view.cc b/ash/system/accessibility/switch_access/switch_access_back_button_view.cc similarity index 97% rename from ash/system/accessibility/switch_access_back_button_view.cc rename to ash/system/accessibility/switch_access/switch_access_back_button_view.cc index 763c5f9..0e14318 100644 --- a/ash/system/accessibility/switch_access_back_button_view.cc +++ b/ash/system/accessibility/switch_access/switch_access_back_button_view.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_back_button_view.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_view.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/system/accessibility/switch_access_back_button_view.h b/ash/system/accessibility/switch_access/switch_access_back_button_view.h similarity index 85% rename from ash/system/accessibility/switch_access_back_button_view.h rename to ash/system/accessibility/switch_access/switch_access_back_button_view.h index 2b23d9b..88d4023 100644 --- a/ash/system/accessibility/switch_access_back_button_view.h +++ b/ash/system/accessibility/switch_access/switch_access_back_button_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/layout/box_layout_view.h" @@ -53,4 +53,4 @@ DEFINE_VIEW_BUILDER(/* no export */, ash::SwitchAccessBackButtonView) -#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_BACK_BUTTON_VIEW_H_
diff --git a/ash/system/accessibility/switch_access_menu_bubble_controller.cc b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.cc similarity index 94% rename from ash/system/accessibility/switch_access_menu_bubble_controller.cc rename to ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.cc index 6b268707..8c98b01 100644 --- a/ash/system/accessibility/switch_access_menu_bubble_controller.cc +++ b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_menu_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/accessibility/switch_access_back_button_bubble_controller.h" -#include "ash/system/accessibility/switch_access_menu_view.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_view.h" #include "ash/system/tray/tray_background_view.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/unified/unified_system_tray_view.h"
diff --git a/ash/system/accessibility/switch_access_menu_bubble_controller.h b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h similarity index 84% rename from ash/system/accessibility/switch_access_menu_bubble_controller.h rename to ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h index 4a629f6..cbbf7212 100644 --- a/ash/system/accessibility/switch_access_menu_bubble_controller.h +++ b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_ #include "ash/system/tray/tray_bubble_view.h" @@ -53,4 +53,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUBBLE_CONTROLLER_H_
diff --git a/ash/system/accessibility/switch_access_menu_bubble_controller_unittest.cc b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller_unittest.cc similarity index 92% rename from ash/system/accessibility/switch_access_menu_bubble_controller_unittest.cc rename to ash/system/accessibility/switch_access/switch_access_menu_bubble_controller_unittest.cc index 303f8c4..0e35f1c7 100644 --- a/ash/system/accessibility/switch_access_menu_bubble_controller_unittest.cc +++ b/ash/system/accessibility/switch_access/switch_access_menu_bubble_controller_unittest.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_menu_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_bubble_controller.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/shell.h" -#include "ash/system/accessibility/switch_access_back_button_bubble_controller.h" -#include "ash/system/accessibility/switch_access_back_button_view.h" -#include "ash/system/accessibility/switch_access_menu_button.h" -#include "ash/system/accessibility/switch_access_menu_view.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_bubble_controller.h" +#include "ash/system/accessibility/switch_access/switch_access_back_button_view.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_button.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_view.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/system/accessibility/switch_access_menu_button.cc b/ash/system/accessibility/switch_access/switch_access_menu_button.cc similarity index 97% rename from ash/system/accessibility/switch_access_menu_button.cc rename to ash/system/accessibility/switch_access/switch_access_menu_button.cc index 965a9e1..5c8f156d 100644 --- a/ash/system/accessibility/switch_access_menu_button.cc +++ b/ash/system/accessibility/switch_access/switch_access_menu_button.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_menu_button.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_button.h" #include "ash/style/ash_color_provider.h" #include "base/bind.h"
diff --git a/ash/system/accessibility/switch_access_menu_button.h b/ash/system/accessibility/switch_access/switch_access_menu_button.h similarity index 85% rename from ash/system/accessibility/switch_access_menu_button.h rename to ash/system/accessibility/switch_access/switch_access_menu_button.h index 3af0b4bb..819c6cf 100644 --- a/ash/system/accessibility/switch_access_menu_button.h +++ b/ash/system/accessibility/switch_access/switch_access_menu_button.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUTTON_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUTTON_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUTTON_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUTTON_H_ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" @@ -56,4 +56,4 @@ DEFINE_VIEW_BUILDER(/* no export */, ash::SwitchAccessMenuButton) -#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_BUTTON_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_BUTTON_H_
diff --git a/ash/system/accessibility/switch_access_menu_view.cc b/ash/system/accessibility/switch_access/switch_access_menu_view.cc similarity index 97% rename from ash/system/accessibility/switch_access_menu_view.cc rename to ash/system/accessibility/switch_access/switch_access_menu_view.cc index 7ae9dd9..191720b 100644 --- a/ash/system/accessibility/switch_access_menu_view.cc +++ b/ash/system/accessibility/switch_access/switch_access_menu_view.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/accessibility/switch_access_menu_view.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_view.h" #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/accessibility/switch_access_menu_button.h" +#include "ash/system/accessibility/switch_access/switch_access_menu_button.h" #include "ash/system/tray/tray_constants.h" #include "base/containers/flat_map.h" #include "base/no_destructor.h"
diff --git a/ash/system/accessibility/switch_access_menu_view.h b/ash/system/accessibility/switch_access/switch_access_menu_view.h similarity index 79% rename from ash/system/accessibility/switch_access_menu_view.h rename to ash/system/accessibility/switch_access/switch_access_menu_view.h index 0643cf1..08a0367 100644 --- a/ash/system/accessibility/switch_access_menu_view.h +++ b/ash/system/accessibility/switch_access/switch_access_menu_view.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_VIEW_H_ -#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_VIEW_H_ +#ifndef ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_VIEW_H_ +#define ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_VIEW_H_ #include <vector> @@ -34,4 +34,4 @@ } // namespace ash -#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_MENU_VIEW_H_ +#endif // ASH_SYSTEM_ACCESSIBILITY_SWITCH_ACCESS_SWITCH_ACCESS_MENU_VIEW_H_
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index 03a1591c..5f068f1 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc
@@ -16,7 +16,7 @@ #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/system/accessibility/dictation_button_tray.h" -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/system/holding_space/holding_space_tray.h" #include "ash/system/ime_menu/ime_menu_tray.h" #include "ash/system/media/media_tray.h"
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc index bb3a80c..e6c75f7 100644 --- a/ash/system/status_area_widget_unittest.cc +++ b/ash/system/status_area_widget_unittest.cc
@@ -18,7 +18,7 @@ #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" #include "ash/system/accessibility/dictation_button_tray.h" -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/system/ime_menu/ime_menu_tray.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/model/virtual_keyboard_model.h"
diff --git a/ash/system/unified/system_tray_test_api.cc b/ash/system/unified/system_tray_test_api.cc index 72e9b40..c6ecfbd 100644 --- a/ash/system/unified/system_tray_test_api.cc +++ b/ash/system/unified/system_tray_test_api.cc
@@ -8,7 +8,7 @@ #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/accessibility/select_to_speak_tray.h" +#include "ash/system/accessibility/select_to_speak/select_to_speak_tray.h" #include "ash/system/status_area_widget.h" #include "ash/system/time/time_tray_item_view.h" #include "ash/system/time/time_view.h"
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 60e7888..837ba95 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -391,7 +391,12 @@ } wm::ActivateWindow(window_state->window()); })); - window->Show(); + // If we are in split mode, use Show() here to delegate un-minimizing to + // SplitViewController as it handles auto snapping cases. + if (SplitViewController::Get(window)->InSplitViewMode()) + window->Show(); + else + window_state->Unminimize(); return; }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index c914e10..ad6f27f 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -155,27 +155,28 @@ DISALLOW_COPY_AND_ASSIGN(TweenTester); }; -// Class which tracks if a given widget has been closed. -class TestClosedWidgetObserver : public views::WidgetObserver { +// Class which tracks if a given widget has been destroyed. +class TestDestroyedWidgetObserver : public views::WidgetObserver { public: - explicit TestClosedWidgetObserver(views::Widget* widget) { + explicit TestDestroyedWidgetObserver(views::Widget* widget) { DCHECK(widget); observation_.Observe(widget); } - TestClosedWidgetObserver(const TestClosedWidgetObserver&) = delete; - TestClosedWidgetObserver& operator=(const TestClosedWidgetObserver&) = delete; - ~TestClosedWidgetObserver() override = default; + TestDestroyedWidgetObserver(const TestDestroyedWidgetObserver&) = delete; + TestDestroyedWidgetObserver& operator=(const TestDestroyedWidgetObserver&) = + delete; + ~TestDestroyedWidgetObserver() override = default; // views::WidgetObserver: - void OnWidgetClosing(views::Widget* widget) override { - DCHECK(!widget_closed_); - widget_closed_ = true; + void OnWidgetDestroyed(views::Widget* widget) override { + DCHECK(!widget_destroyed_); + widget_destroyed_ = true; } - bool widget_closed() const { return widget_closed_; } + bool widget_destroyed() const { return widget_destroyed_; } private: - bool widget_closed_ = false; + bool widget_destroyed_ = false; base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{ this}; @@ -3259,22 +3260,27 @@ ToggleOverview(); } -// Tests that closing the overview item closes the entire transient tree. +// Tests that closing the overview item destroys the entire transient tree. Note +// that closing does not destroy transient children which are ShellSurfaceBase, +// but this test covers the regular case. TEST_F(OverviewSessionTest, ClosingTransientTree) { auto widget = CreateTestWidget(); aura::Window* window = widget->GetNativeWindow(); auto child_widget = CreateTestWidget(); ::wm::AddTransientChild(window, child_widget->GetNativeWindow()); - TestClosedWidgetObserver widget_observer(widget.get()); - TestClosedWidgetObserver child_widget_observer(child_widget.get()); + TestDestroyedWidgetObserver widget_observer(widget.get()); + TestDestroyedWidgetObserver child_widget_observer(child_widget.get()); ToggleOverview(); OverviewItem* item = GetOverviewItemForWindow(window); item->CloseWindow(); - EXPECT_TRUE(widget_observer.widget_closed()); - EXPECT_TRUE(child_widget_observer.widget_closed()); + // `NativeWidgetAura::Close()` fires a post task. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(widget_observer.widget_destroyed()); + EXPECT_TRUE(child_widget_observer.widget_destroyed()); } class TabletModeOverviewSessionTest : public OverviewSessionTest {
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index 99dd92d..9e47192e 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -595,13 +595,9 @@ } void ScopedOverviewTransformWindow::CloseWidget() { - // Close all the windows in the transient tree. Note that is only really - // necessary for exo windows, as non-exo windows we would only need to close - // the tranisent root. We will close all widgets in the tree for both exo and - // non-exo anyways to simplify things and Widget::CloseWithReason handles this - // nicely. - for (auto* transient : GetTransientTreeIterator(window_)) - window_util::CloseWidgetForWindow(transient); + aura::Window* parent_window = wm::GetTransientRoot(window_); + if (parent_window) + window_util::CloseWidgetForWindow(parent_window); } void ScopedOverviewTransformWindow::AddHiddenTransientWindows(
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc index 91d0ad3..049fda0 100644 --- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc +++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -258,7 +258,9 @@ if (alignment <= base::kAlignment) { // This is mandated by |posix_memalign()| and friends, so should never fire. PA_CHECK(base::bits::IsPowerOfTwo(alignment)); - return Allocator()->AllocFlagsNoHooks(0, size); + // TODO(bartekn): See if the compiler optimizes branches down the stack on + // Mac, where PartitionPageSize() isn't constexpr. + return Allocator()->AllocFlagsNoHooks(0, size, base::PartitionPageSize()); } return AlignedAllocator()->AlignedAllocFlags(base::PartitionAllocNoHooks, @@ -271,14 +273,16 @@ namespace internal { void* PartitionMalloc(const AllocatorDispatch*, size_t size, void* context) { - return Allocator()->AllocFlagsNoHooks(0, MaybeAdjustSize(size)); + return Allocator()->AllocFlagsNoHooks(0, MaybeAdjustSize(size), + PartitionPageSize()); } void* PartitionMallocUnchecked(const AllocatorDispatch*, size_t size, void* context) { return Allocator()->AllocFlagsNoHooks(base::PartitionAllocReturnNull, - MaybeAdjustSize(size)); + MaybeAdjustSize(size), + PartitionPageSize()); } void* PartitionCalloc(const AllocatorDispatch*, @@ -286,7 +290,8 @@ size_t size, void* context) { const size_t total = base::CheckMul(n, MaybeAdjustSize(size)).ValueOrDie(); - return Allocator()->AllocFlagsNoHooks(base::PartitionAllocZeroFill, total); + return Allocator()->AllocFlagsNoHooks(base::PartitionAllocZeroFill, total, + PartitionPageSize()); } void* PartitionMemalign(const AllocatorDispatch*,
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc index e368a440..19e0466 100644 --- a/base/allocator/partition_allocator/address_pool_manager.cc +++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -279,7 +279,7 @@ char* AddressPoolManager::Reserve(pool_handle handle, void* requested_address, size_t length) { - PA_DCHECK(!(length & PageAllocationGranularityOffsetMask())); + PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask())); char* ptr = reinterpret_cast<char*>( AllocPages(requested_address, length, kSuperPageSize, PageInaccessible, PageTag::kPartitionAlloc)); @@ -295,7 +295,7 @@ size_t length) { uintptr_t ptr_as_uintptr = reinterpret_cast<uintptr_t>(ptr); PA_DCHECK(!(ptr_as_uintptr & kSuperPageOffsetMask)); - PA_DCHECK(!(length & PageAllocationGranularityOffsetMask())); + PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask())); MarkUnused(handle, ptr_as_uintptr, length); FreePages(ptr, length); } @@ -307,8 +307,8 @@ AutoLock guard(AddressPoolManagerBitmap::GetLock()); if (handle == kNonBRPPoolHandle) { SetBitmap(AddressPoolManagerBitmap::non_brp_pool_bits_, - ptr_as_uintptr / PageAllocationGranularity(), - length / PageAllocationGranularity()); + ptr_as_uintptr / DirectMapAllocationGranularity(), + length / DirectMapAllocationGranularity()); } else { PA_DCHECK(handle == kBRPPoolHandle); PA_DCHECK(!(length & kSuperPageOffsetMask)); @@ -352,8 +352,8 @@ // allocated from there. Thus LIKELY is used. if (LIKELY(handle == kNonBRPPoolHandle)) { ResetBitmap(AddressPoolManagerBitmap::non_brp_pool_bits_, - address / PageAllocationGranularity(), - length / PageAllocationGranularity()); + address / DirectMapAllocationGranularity(), + length / DirectMapAllocationGranularity()); } else { PA_DCHECK(handle == kBRPPoolHandle); PA_DCHECK(!(length & kSuperPageOffsetMask));
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.h b/base/allocator/partition_allocator/address_pool_manager_bitmap.h index c3f949b..00a9078f 100644 --- a/base/allocator/partition_allocator/address_pool_manager_bitmap.h +++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
@@ -43,16 +43,17 @@ kAddressSpaceSize / kBytesPer1BitOfBRPPoolBitmap; // Non-BRP pool includes both normal bucket and direct map allocations, so - // PageAllocationGranularity() has to be used. No need to eliminate guard + // DirectMapAllocationGranularity() has to be used. No need to eliminate guard // pages at the ends, as this is a BackupRefPtr-specific concern. static constexpr size_t kNonBRPPoolBits = - kAddressSpaceSize / PageAllocationGranularity(); + kAddressSpaceSize / DirectMapAllocationGranularity(); // Returns false for nullptr. static bool IsManagedByNonBRPPool(const void* address) { uintptr_t address_as_uintptr = reinterpret_cast<uintptr_t>(address); static_assert( - std::numeric_limits<uintptr_t>::max() / PageAllocationGranularity() < + std::numeric_limits<uintptr_t>::max() / + DirectMapAllocationGranularity() < non_brp_pool_bits_.size(), "The bitmap is too small, will result in unchecked out of bounds " "accesses."); @@ -60,7 +61,8 @@ // is responsible for guaranteeing that the address is inside a valid // allocation and the deallocation call won't race with this call. return TS_UNCHECKED_READ( - non_brp_pool_bits_)[address_as_uintptr / PageAllocationGranularity()]; + non_brp_pool_bits_)[address_as_uintptr / + DirectMapAllocationGranularity()]; } // Returns false for nullptr.
diff --git a/base/allocator/partition_allocator/address_pool_manager_unittest.cc b/base/allocator/partition_allocator/address_pool_manager_unittest.cc index ab4c2257..854ba5be 100644 --- a/base/allocator/partition_allocator/address_pool_manager_unittest.cc +++ b/base/allocator/partition_allocator/address_pool_manager_unittest.cc
@@ -192,16 +192,18 @@ void* addrs[kAllocCount]; for (size_t i = 0; i < kAllocCount; ++i) { addrs[i] = AddressPoolManager::GetInstance()->Reserve( - GetNonBRPPool(), nullptr, PageAllocationGranularity() * kNumPages[i]); + GetNonBRPPool(), nullptr, + DirectMapAllocationGranularity() * kNumPages[i]); EXPECT_TRUE(addrs[i]); EXPECT_TRUE( !(reinterpret_cast<uintptr_t>(addrs[i]) & kSuperPageOffsetMask)); } for (size_t i = 0; i < kAllocCount; ++i) { const char* ptr = reinterpret_cast<const char*>(addrs[i]); - size_t num_pages = bits::AlignUp(kNumPages[i] * PageAllocationGranularity(), - kSuperPageSize) / - PageAllocationGranularity(); + size_t num_pages = + bits::AlignUp(kNumPages[i] * DirectMapAllocationGranularity(), + kSuperPageSize) / + DirectMapAllocationGranularity(); for (size_t j = 0; j < num_pages; ++j) { if (j < kNumPages[i]) { EXPECT_TRUE(AddressPoolManager::IsManagedByNonBRPPool(ptr)); @@ -209,12 +211,13 @@ EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(ptr)); } EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(ptr)); - ptr += PageAllocationGranularity(); + ptr += DirectMapAllocationGranularity(); } } for (size_t i = 0; i < kAllocCount; ++i) { AddressPoolManager::GetInstance()->UnreserveAndDecommit( - GetNonBRPPool(), addrs[i], PageAllocationGranularity() * kNumPages[i]); + GetNonBRPPool(), addrs[i], + DirectMapAllocationGranularity() * kNumPages[i]); EXPECT_FALSE(AddressPoolManager::IsManagedByNonBRPPool(addrs[i])); EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(addrs[i])); }
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc index 882b6ba6..3f73926 100644 --- a/base/allocator/partition_allocator/partition_alloc.cc +++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -52,7 +52,7 @@ // Limit to prevent callers accidentally overflowing an int size. STATIC_ASSERT_OR_PA_CHECK( - MaxDirectMapped() <= (1UL << 31) + PageAllocationGranularity(), + MaxDirectMapped() <= (1UL << 31) + DirectMapAllocationGranularity(), "maximum direct mapped allocation"); // Check that some of our zanier calculations worked out as expected.
diff --git a/base/allocator/partition_allocator/partition_alloc_constants.h b/base/allocator/partition_allocator/partition_alloc_constants.h index 73f3566f..b08d32c 100644 --- a/base/allocator/partition_allocator/partition_alloc_constants.h +++ b/base/allocator/partition_allocator/partition_alloc_constants.h
@@ -12,6 +12,7 @@ #include "base/allocator/buildflags.h" #include "base/allocator/partition_allocator/page_allocator_constants.h" +#include "base/allocator/partition_allocator/partition_alloc_config.h" #include "build/build_config.h" #if defined(OS_APPLE) @@ -185,6 +186,28 @@ return kSuperPageSize / PartitionPageSize(); } +#if defined(PA_HAS_64_BITS_POINTERS) +// In 64-bit mode, the direct map allocation granularity is super page size, +// because this is the reservation granularit of the GigaCage. +constexpr ALWAYS_INLINE size_t DirectMapAllocationGranularity() { + return kSuperPageSize; +} +#else +// In 32-bit mode, address space is space is a scarce resource. Use the system +// allocation granularity, which is the lowest possible address space allocation +// unit. However, don't go below partition page size, so that GigaCage bitmaps +// don't get too large. +PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t +DirectMapAllocationGranularity() { + return std::max(PageAllocationGranularity(), PartitionPageSize()); +} +#endif // defined(PA_HAS_64_BITS_POINTERS) + +PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t +DirectMapAllocationGranularityOffsetMask() { + return DirectMapAllocationGranularity() - 1; +} + // Alignment has two constraints: // - Alignment requirement for scalar types: alignof(std::max_align_t) // - Alignment requirement for operator new(). @@ -248,10 +271,16 @@ // crbug.com/998048 for details. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR ALWAYS_INLINE size_t MaxDirectMapped() { - // Subtract kSuperPageSize to accommodate for alignment inside + // Subtract kSuperPageSize to accommodate for granularity inside // PartitionRoot::GetDirectMapReservedSize. return (1UL << 31) - kSuperPageSize; } + +// Max alignment supported by AlignedAllocFlags(). +// kSuperPageSize alignment can't be easily supported, because each super page +// starts with guard pages & metadata. +static const size_t kMaxSupportedAlignment = kSuperPageSize / 2; + static const size_t kBitsPerSizeT = sizeof(void*) * CHAR_BIT; // Constant for the memory reclaim logic.
diff --git a/base/allocator/partition_allocator/partition_alloc_perftest.cc b/base/allocator/partition_allocator/partition_alloc_perftest.cc index 545dd80..c4e4d56 100644 --- a/base/allocator/partition_allocator/partition_alloc_perftest.cc +++ b/base/allocator/partition_allocator/partition_alloc_perftest.cc
@@ -85,7 +85,7 @@ ~PartitionAllocator() override = default; void* Alloc(size_t size) override { - return alloc_.AllocFlagsNoHooks(0, size); + return alloc_.AllocFlagsNoHooks(0, size, PartitionPageSize()); } void Free(void* data) override { ThreadSafePartitionRoot::FreeNoHooks(data); } @@ -115,7 +115,7 @@ ~PartitionAllocatorWithThreadCache() override = default; void* Alloc(size_t size) override { - return g_partition_root->AllocFlagsNoHooks(0, size); + return g_partition_root->AllocFlagsNoHooks(0, size, PartitionPageSize()); } void Free(void* data) override { ThreadSafePartitionRoot::FreeNoHooks(data); } };
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc index 11fadd7..36d608b 100644 --- a/base/allocator/partition_allocator/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -2609,7 +2609,7 @@ TEST_F(PartitionAllocTest, Alignment) { std::vector<void*> allocated_ptrs; - for (size_t size = 1; size <= base::SystemPageSize(); size <<= 1) { + for (size_t size = 1; size <= base::PartitionPageSize(); size <<= 1) { // All allocations which are not direct-mapped occupy contiguous slots of a // span, starting on a page boundary. This means that allocations are first // rounded up to the nearest bucket size, then have an address of the form: @@ -2714,11 +2714,12 @@ #define MAYBE_AlignedAllocations AlignedAllocations #endif TEST_F(PartitionAllocTest, MAYBE_AlignedAllocations) { - size_t alloc_sizes[] = {1, 10, 100, 1000, 10000, 100000, 1000000}; - size_t alignemnts[] = {8, 16, 32, 64, 256, 1024, 4096, 8192}; + size_t alloc_sizes[] = {1, 10, 100, 1000, 10000, + 60000, 70000, 130000, 500000, 900000}; + size_t max_alignment = 1048576; for (size_t alloc_size : alloc_sizes) { - for (size_t alignment : alignemnts) { + for (size_t alignment = 1; alignment <= max_alignment; alignment <<= 1) { VerifyAlignment(aligned_allocator.root(), alloc_size, alignment); // AlignedAllocFlags() can't be called on regular allocator, if there are @@ -2862,6 +2863,7 @@ kSuperPageSize + PartitionPageSize(), kSuperPageSize + SystemPageSize() + PartitionPageSize(), kSuperPageSize + PageAllocationGranularity(), + kSuperPageSize + DirectMapAllocationGranularity(), }; for (size_t huge_size : huge_sizes) { // For direct map, we commit only as many pages as needed. @@ -2870,12 +2872,9 @@ expected_committed_size += aligned_size; size_t surrounding_pages_size = PartitionRoot<ThreadSafe>::GetDirectMapMetadataAndGuardPagesSize(); - size_t alignment = PageAllocationGranularity(); -#if defined(PA_HAS_64_BITS_POINTERS) - alignment = kSuperPageSize; -#endif size_t expected_direct_map_size = - bits::AlignUp(aligned_size + surrounding_pages_size, alignment); + bits::AlignUp(aligned_size + surrounding_pages_size, + DirectMapAllocationGranularity()); EXPECT_EQ(expected_committed_size, root.total_size_of_committed_pages); EXPECT_EQ(expected_super_pages_size, root.total_size_of_super_pages); EXPECT_EQ(expected_direct_map_size, root.total_size_of_direct_mapped_pages); @@ -3032,24 +3031,24 @@ size_t allocation_size = 64; // The very first allocation is never a fast path one, since it needs a new // super page and a new partition page. - EXPECT_FALSE(allocator.root()->AllocFlagsNoHooks( - PartitionAllocFastPathOrReturnNull, allocation_size)); - void* ptr = allocator.root()->AllocFlagsNoHooks(0, allocation_size); + EXPECT_FALSE(allocator.root()->AllocFlags(PartitionAllocFastPathOrReturnNull, + allocation_size, "")); + void* ptr = allocator.root()->AllocFlags(0, allocation_size, ""); ASSERT_TRUE(ptr); // Next one is, since the partition page has been activated. - void* ptr2 = allocator.root()->AllocFlagsNoHooks( - PartitionAllocFastPathOrReturnNull, allocation_size); + void* ptr2 = allocator.root()->AllocFlags(PartitionAllocFastPathOrReturnNull, + allocation_size, ""); EXPECT_TRUE(ptr2); // First allocation of a different bucket is slow. - EXPECT_FALSE(allocator.root()->AllocFlagsNoHooks( - PartitionAllocFastPathOrReturnNull, 2 * allocation_size)); + EXPECT_FALSE(allocator.root()->AllocFlags(PartitionAllocFastPathOrReturnNull, + 2 * allocation_size, "")); size_t allocated_size = 2 * allocation_size; std::vector<void*> ptrs; - while (void* new_ptr = allocator.root()->AllocFlagsNoHooks( - PartitionAllocFastPathOrReturnNull, allocation_size)) { + while (void* new_ptr = allocator.root()->AllocFlags( + PartitionAllocFastPathOrReturnNull, allocation_size, "")) { ptrs.push_back(new_ptr); allocated_size += allocation_size; }
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc index f658a731..0bdd2f1 100644 --- a/base/allocator/partition_allocator/partition_bucket.cc +++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -153,12 +153,11 @@ PA_DCHECK(!metadata->extent.super_page_base); PA_DCHECK(!metadata->extent.super_pages_end); PA_DCHECK(!metadata->extent.next); - // Call FromSlotInnerPtr instead of FromSlotStartPtr, because the bucket - // isn't set up yet to properly assert the slot start. - PA_DCHECK(PartitionPage<thread_safe>::FromSlotInnerPtr(slot) == - &metadata->page); + PA_DCHECK(PartitionPage<thread_safe>::FromPtr(slot) == &metadata->page); page = &metadata->page; + page->is_valid = true; + PA_DCHECK(!page->has_valid_span_after_this); PA_DCHECK(!page->slot_span_metadata_offset); PA_DCHECK(!page->slot_span_metadata.next_slot_span); PA_DCHECK(!page->slot_span_metadata.num_allocated_slots); @@ -279,7 +278,8 @@ template <bool thread_safe> ALWAYS_INLINE SlotSpanMetadata<thread_safe>* PartitionBucket<thread_safe>::AllocNewSlotSpan(PartitionRoot<thread_safe>* root, - int flags) { + int flags, + size_t slot_span_alignment) { PA_DCHECK(!(reinterpret_cast<uintptr_t>(root->next_partition_page) % PartitionPageSize())); PA_DCHECK(!(reinterpret_cast<uintptr_t>(root->next_partition_page_end) % @@ -292,25 +292,39 @@ PA_DCHECK(slot_span_committed_size % SystemPageSize() == 0); PA_DCHECK(slot_span_committed_size <= slot_span_reserved_size); - size_t num_partition_pages_left = - (root->next_partition_page_end - root->next_partition_page) >> - PartitionPageShift(); - if (UNLIKELY(num_partition_pages_left < num_partition_pages)) { + auto adjusted_next_partition_page = + bits::AlignUp(root->next_partition_page, slot_span_alignment); + if (UNLIKELY(adjusted_next_partition_page + slot_span_reserved_size > + root->next_partition_page_end)) { // In this case, we can no longer hand out pages from the current super page // allocation. Get a new super page. if (!AllocNewSuperPage(root)) { return nullptr; } + // AllocNewSuperPage() updates root->next_partition_page, re-query. + adjusted_next_partition_page = + bits::AlignUp(root->next_partition_page, slot_span_alignment); + PA_CHECK(adjusted_next_partition_page + slot_span_reserved_size <= + root->next_partition_page_end); } - void* slot_span_start = root->next_partition_page; - root->next_partition_page += slot_span_reserved_size; + auto* gap_start_page = + PartitionPage<thread_safe>::FromPtr(root->next_partition_page); + auto* gap_end_page = + PartitionPage<thread_safe>::FromPtr(adjusted_next_partition_page); + for (auto* page = gap_start_page; page < gap_end_page; ++page) { + PA_DCHECK(!page->is_valid); + page->has_valid_span_after_this = 1; + } + root->next_partition_page = + adjusted_next_partition_page + slot_span_reserved_size; - // Call FromSlotInnerPtr instead of FromSlotStartPtr, because the slot_span's - // bucket isn't set up yet to properly assert the slot start. - auto* slot_span = - SlotSpanMetadata<thread_safe>::FromSlotInnerPtr(slot_span_start); + void* slot_span_start = adjusted_next_partition_page; + auto* slot_span = &gap_end_page->slot_span_metadata; InitializeSlotSpan(slot_span); + // Now that slot span is initialized, it's safe to call FromSlotStartPtr. + PA_DCHECK(slot_span == + SlotSpanMetadata<thread_safe>::FromSlotStartPtr(slot_span_start)); // System pages in the super page come in a decommited state. Commit them // before vending them back. @@ -483,9 +497,10 @@ uint16_t num_partition_pages = get_pages_per_slot_span(); auto* page = reinterpret_cast<PartitionPage<thread_safe>*>(slot_span); - for (uint16_t i = 1; i < num_partition_pages; ++i) { - auto* secondary_page = page + i; - secondary_page->slot_span_metadata_offset = i; + for (uint16_t i = 0; i < num_partition_pages; ++i, ++page) { + PA_DCHECK(i <= PartitionPage<thread_safe>::kMaxSlotSpanMetadataOffset); + page->slot_span_metadata_offset = i; + page->is_valid = true; } } @@ -633,9 +648,17 @@ PartitionRoot<thread_safe>* root, int flags, size_t raw_size, + size_t slot_span_alignment, bool* is_already_zeroed) { - // The slow path is called when the freelist is empty. - PA_DCHECK(!active_slot_spans_head->freelist_head); + PA_DCHECK(slot_span_alignment && + !(slot_span_alignment & PartitionPageOffsetMask())); + + // The slow path is called when the freelist is empty. The only exception is + // when a higher-order alignment is requested, in which case the freelist + // logic is bypassed and we go directly for slot span allocation. + bool allocate_aligned_slot_span = slot_span_alignment > PartitionPageSize(); + PA_DCHECK(!active_slot_spans_head->freelist_head || + allocate_aligned_slot_span); SlotSpanMetadata<thread_safe>* new_slot_span = nullptr; // |new_slot_span->bucket| will always be |this|, except when |this| is the @@ -659,6 +682,7 @@ PA_DCHECK(this == &root->sentinel_bucket); PA_DCHECK(active_slot_spans_head == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()); + PA_DCHECK(!allocate_aligned_slot_span); // not supported for direct map // No fast path for direct-mapped allocations. if (flags & PartitionAllocFastPathOrReturnNull) @@ -669,12 +693,13 @@ new_bucket = new_slot_span->bucket; // Memory from PageAllocator is always zeroed. *is_already_zeroed = true; - } else if (LIKELY(SetNewActiveSlotSpan())) { + } else if (LIKELY(!allocate_aligned_slot_span && SetNewActiveSlotSpan())) { // First, did we find an active slot span in the active list? new_slot_span = active_slot_spans_head; PA_DCHECK(new_slot_span->is_active()); - } else if (LIKELY(empty_slot_spans_head != nullptr) || - LIKELY(decommitted_slot_spans_head != nullptr)) { + } else if (LIKELY(!allocate_aligned_slot_span && + (empty_slot_spans_head != nullptr || + decommitted_slot_spans_head != nullptr))) { // Second, look in our lists of empty and decommitted slot spans. // Check empty slot spans first, which are preferred, but beware that an // empty slot span might have been decommitted. @@ -732,7 +757,7 @@ // Third. If we get here, we need a brand new slot span. // TODO(bartekn): For single-slot slot spans, we can use rounded raw_size // as slot_span_committed_size. - new_slot_span = AllocNewSlotSpan(root, flags); + new_slot_span = AllocNewSlotSpan(root, flags, slot_span_alignment); // New memory from PageAllocator is always zeroed. *is_already_zeroed = true; }
diff --git a/base/allocator/partition_allocator/partition_bucket.h b/base/allocator/partition_allocator/partition_bucket.h index ac3a8e3..0f4b844 100644 --- a/base/allocator/partition_allocator/partition_bucket.h +++ b/base/allocator/partition_allocator/partition_bucket.h
@@ -61,6 +61,7 @@ BASE_EXPORT NOINLINE void* SlowPathAlloc(PartitionRoot<thread_safe>* root, int flags, size_t raw_size, + size_t slot_span_alignment, bool* is_already_zeroed) EXCLUSIVE_LOCKS_REQUIRED(root->lock_); @@ -148,7 +149,8 @@ // Returns nullptr on error. ALWAYS_INLINE SlotSpanMetadata<thread_safe>* AllocNewSlotSpan( PartitionRoot<thread_safe>* root, - int flags) EXCLUSIVE_LOCKS_REQUIRED(root->lock_); + int flags, + size_t slot_span_alignment) EXCLUSIVE_LOCKS_REQUIRED(root->lock_); // Allocates a new super page from the current extent. All slot-spans will be // in the decommitted state. Returns nullptr on error.
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc index 0e36927..65f88e2 100644 --- a/base/allocator/partition_allocator/partition_page.cc +++ b/base/allocator/partition_allocator/partition_page.cc
@@ -47,10 +47,10 @@ size_t reserved_size = extent->map_size + PartitionRoot<thread_safe>::GetDirectMapMetadataAndGuardPagesSize(); - PA_DCHECK(!(reserved_size & PageAllocationGranularityOffsetMask())); + PA_DCHECK(!(reserved_size & DirectMapAllocationGranularityOffsetMask())); PA_DCHECK(root->total_size_of_direct_mapped_pages >= reserved_size); root->total_size_of_direct_mapped_pages -= reserved_size; - PA_DCHECK(!(reserved_size & PageAllocationGranularityOffsetMask())); + PA_DCHECK(!(reserved_size & DirectMapAllocationGranularityOffsetMask())); char* ptr = reinterpret_cast<char*>( SlotSpanMetadata<thread_safe>::ToSlotSpanStartPtr(slot_span));
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h index cf2d615b..a19d74ae 100644 --- a/base/allocator/partition_allocator/partition_page.h +++ b/base/allocator/partition_allocator/partition_page.h
@@ -6,6 +6,7 @@ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_PAGE_H_ #include <string.h> +#include <cstdint> #include <limits> #include "base/allocator/partition_allocator/address_pool_manager.h" @@ -231,7 +232,7 @@ // information. template <bool thread_safe> struct PartitionPage { - // "Pack" the union so that slot_span_metadata_offset still fits within + // "Pack" the union so that common page metadata still fits within // kPageMetadataSize. (SlotSpanMetadata is also "packed".) union __attribute__((packed)) { SlotSpanMetadata<thread_safe> slot_span_metadata; @@ -243,15 +244,28 @@ // - below kPageMetadataSize // // This makes sure that this is respected no matter the architecture. - char optional_padding[kPageMetadataSize - sizeof(uint16_t)]; + char optional_padding[kPageMetadataSize - sizeof(uint8_t) - sizeof(bool)]; }; // The first PartitionPage of the slot span holds its metadata. This offset // tells how many pages in from that first page we are. - uint16_t slot_span_metadata_offset; + // 6 bits is enough to represent all possible offsets, given that the smallest + // partition page is 16kiB and normal buckets won't exceed 1MiB. + static constexpr uint16_t kMaxSlotSpanMetadataBits = 6; + static constexpr uint16_t kMaxSlotSpanMetadataOffset = + (1 << kMaxSlotSpanMetadataBits) - 1; + uint8_t slot_span_metadata_offset; - ALWAYS_INLINE static PartitionPage* FromSlotStartPtr(void* slot_start); - ALWAYS_INLINE static PartitionPage* FromSlotInnerPtr(void* ptr); + // |is_valid| tells whether the page is part of a slot span. If |false|, + // |has_valid_span_after_this| tells whether it's an unused region in between + // slot spans within the super page. + // Note, |is_valid| has been added for clarity, but if we ever need to save + // this bit, it can be inferred from: + // |!slot_span_metadata_offset && slot_span_metadata->bucket|. + bool is_valid : 1; + bool has_valid_span_after_this : 1; + + ALWAYS_INLINE static PartitionPage* FromPtr(void* slot_start); private: ALWAYS_INLINE static void* ToSlotSpanStartPtr(const PartitionPage* page); @@ -327,12 +341,12 @@ // CAUTION! Use only for normal buckets. Using on direct-mapped allocations may // lead to undefined behavior. -ALWAYS_INLINE bool IsWithinSuperPagePayload(char* ptr, bool with_quarantine) { +ALWAYS_INLINE bool IsWithinSuperPagePayload(void* ptr, bool with_quarantine) { // TODO(bartekn): Add a "is in normal buckets" DCHECK. char* super_page_base = reinterpret_cast<char*>( reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask); - char* payload_start = SuperPagePayloadBegin(super_page_base, with_quarantine); - char* payload_end = SuperPagePayloadEnd(super_page_base); + void* payload_start = SuperPagePayloadBegin(super_page_base, with_quarantine); + void* payload_end = SuperPagePayloadEnd(super_page_base); return ptr >= payload_start && ptr < payload_end; } @@ -390,21 +404,28 @@ template <bool thread_safe> ALWAYS_INLINE void* PartitionPage<thread_safe>::ToSlotSpanStartPtr( const PartitionPage* page) { + PA_DCHECK(page->is_valid); PA_DCHECK(!page->slot_span_metadata_offset); return SlotSpanMetadata<thread_safe>::ToSlotSpanStartPtr( &page->slot_span_metadata); } -// Converts from a pointer inside a slot into a pointer to the PartitionPage -// object (within super pages's metadata) that describes the first partition -// page of a slot span containing that slot. +// Converts from a pointer inside a super page into a pointer to the +// PartitionPage object (within super pages's metadata) that describes the +// partition page where |ptr| is located. |ptr| doesn't have to be a located +// within a valid (i.e. allocated) slot span, but must be within the super +// page's payload (i.e. region devoted to slot spans). // -// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may -// lead to undefined behavior. +// While it is generally valid for |ptr| to be in the middle of an allocation, +// care has to be taken with direct maps that span multiple super pages. This +// function's behavior is undefined if |ptr| lies in a subsequent super page. template <bool thread_safe> -ALWAYS_INLINE PartitionPage<thread_safe>* -PartitionPage<thread_safe>::FromSlotInnerPtr(void* ptr) { - // TODO(bartekn): Add a "is in normal buckets" DCHECK. +ALWAYS_INLINE PartitionPage<thread_safe>* PartitionPage<thread_safe>::FromPtr( + void* ptr) { + // Force |with_quarantine=false|, because we don't know whether its direct map + // and direct map allocations don't have quarantine bitmaps. + PA_DCHECK(IsWithinSuperPagePayload(ptr, /* with_quarantine= */ false)); + uintptr_t pointer_as_uint = reinterpret_cast<uintptr_t>(ptr); char* super_page_ptr = reinterpret_cast<char*>(pointer_as_uint & kSuperPageBaseMask); @@ -412,32 +433,13 @@ (pointer_as_uint & kSuperPageOffsetMask) >> PartitionPageShift(); // Index 0 is invalid because it is the super page extent metadata and the // last index is invalid because the whole PartitionPage is set as guard - // pages. + // pages. This repeats part of the payload PA_DCHECK above, which may check + // for other exclusions. PA_DCHECK(partition_page_index); PA_DCHECK(partition_page_index < NumPartitionPagesPerSuperPage() - 1); - auto* page = reinterpret_cast<PartitionPage<thread_safe>*>( + return reinterpret_cast<PartitionPage<thread_safe>*>( PartitionSuperPageToMetadataArea(super_page_ptr) + (partition_page_index << kPageMetadataShift)); - // Partition pages in the same slot span share the same slot span metadata - // object (located in the first PartitionPage object of that span). Adjust - // for that. - page -= page->slot_span_metadata_offset; - return page; -} - -// Like |FromSlotInnerPtr|, but asserts that pointer points to the beginning of -// the slot. -template <bool thread_safe> -ALWAYS_INLINE PartitionPage<thread_safe>* -PartitionPage<thread_safe>::FromSlotStartPtr(void* slot_start) { - auto* page = FromSlotInnerPtr(slot_start); - - // Checks that the pointer is a multiple of slot size. - auto* slot_span_start = ToSlotSpanStartPtr(page); - PA_DCHECK(!((reinterpret_cast<uintptr_t>(slot_start) - - reinterpret_cast<uintptr_t>(slot_span_start)) % - page->slot_span_metadata.bucket->slot_size)); - return page; } // Converts from a pointer to the SlotSpanMetadata object (within super pages's @@ -475,10 +477,20 @@ // Converts from a pointer inside a slot into a pointer to the SlotSpanMetadata // object (within super pages's metadata) that describes the slot span // containing that slot. +// +// CAUTION! Use only for normal buckets. Using on direct-mapped allocations may +// lead to undefined behavior. template <bool thread_safe> ALWAYS_INLINE SlotSpanMetadata<thread_safe>* SlotSpanMetadata<thread_safe>::FromSlotInnerPtr(void* ptr) { - auto* page = PartitionPage<thread_safe>::FromSlotInnerPtr(ptr); + // TODO(bartekn): Add a "is in normal buckets" DCHECK. + auto* page = PartitionPage<thread_safe>::FromPtr(ptr); + PA_DCHECK(page->is_valid); + // Partition pages in the same slot span share the same slot span metadata + // object (located in the first PartitionPage object of that span). Adjust + // for that. + page -= page->slot_span_metadata_offset; + PA_DCHECK(page->is_valid); PA_DCHECK(!page->slot_span_metadata_offset); return &page->slot_span_metadata; } @@ -488,9 +500,13 @@ template <bool thread_safe> ALWAYS_INLINE SlotSpanMetadata<thread_safe>* SlotSpanMetadata<thread_safe>::FromSlotStartPtr(void* slot_start) { - auto* page = PartitionPage<thread_safe>::FromSlotStartPtr(slot_start); - PA_DCHECK(!page->slot_span_metadata_offset); - return &page->slot_span_metadata; + auto* slot_span = FromSlotInnerPtr(slot_start); + // Checks that the pointer is a multiple of slot size. + auto* slot_span_start = ToSlotSpanStartPtr(slot_span); + PA_DCHECK(!((reinterpret_cast<uintptr_t>(slot_start) - + reinterpret_cast<uintptr_t>(slot_span_start)) % + slot_span->bucket->slot_size)); + return slot_span; } template <bool thread_safe> @@ -632,21 +648,38 @@ #endif using Page = PartitionPage<thread_safe>; - auto* const first_page = Page::FromSlotStartPtr( - SuperPagePayloadBegin(super_page_base, with_quarantine)); - // Call FromSlotInnerPtr instead of FromSlotStartPtr, because this slot span - // doesn't exist, hence its bucket isn't set up to properly assert the slot - // start. - auto* const last_page = Page::FromSlotInnerPtr( - SuperPagePayloadEnd(super_page_base) - PartitionPageSize()); + using SlotSpan = SlotSpanMetadata<thread_safe>; + auto* const first_page = + Page::FromPtr(SuperPagePayloadBegin(super_page_base, with_quarantine)); + auto* const last_page = + Page::FromPtr(SuperPagePayloadEnd(super_page_base) - PartitionPageSize()); size_t visited = 0; - for (auto* page = first_page; - page <= last_page && page->slot_span_metadata.bucket; - page += page->slot_span_metadata.bucket->get_pages_per_slot_span()) { - auto* slot_span = &page->slot_span_metadata; + Page* page; + SlotSpan* slot_span; + for (page = first_page; page <= last_page;) { + PA_DCHECK(!page->slot_span_metadata_offset); // Ensure slot span beginning. + if (!page->is_valid) { + if (page->has_valid_span_after_this) { + // The page doesn't represent a valid slot span, but there is another + // one somewhere after this. Keep iterating to find it. + ++page; + continue; + } + // There are currently no valid spans from here on. No need to iterate + // the rest of the super page. + break; + } + slot_span = &page->slot_span_metadata; if (callback(slot_span)) ++visited; + page += slot_span->bucket->get_pages_per_slot_span(); } + // Each super page must have at least one valid slot span. + PA_DCHECK(page > first_page); + // Just a quick check that the search ended at a valid slot span and there + // was no unnecessary iteration over gaps afterwards. + PA_DCHECK(page == reinterpret_cast<Page*>(slot_span) + + slot_span->bucket->get_pages_per_slot_span()); return visited; }
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc index 5057cd1..9c97aea 100644 --- a/base/allocator/partition_allocator/partition_root.cc +++ b/base/allocator/partition_allocator/partition_root.cc
@@ -10,6 +10,7 @@ #include "base/allocator/partition_allocator/partition_address_space.h" #include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_config.h" +#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_features.h" #include "base/allocator/partition_allocator/partition_bucket.h" #include "base/allocator/partition_allocator/partition_cookie.h" @@ -767,8 +768,9 @@ #else bool no_hooks = flags & PartitionAllocNoHooks; if (UNLIKELY(!ptr)) { - return no_hooks ? AllocFlagsNoHooks(flags, new_size) - : AllocFlags(flags, new_size, type_name); + return no_hooks ? AllocFlagsNoHooks(flags, new_size, PartitionPageSize()) + : AllocFlagsInternal(flags, new_size, PartitionPageSize(), + type_name); } if (UNLIKELY(!new_size)) { @@ -820,8 +822,9 @@ } // This realloc cannot be resized in-place. Sadness. - void* ret = no_hooks ? AllocFlagsNoHooks(flags, new_size) - : AllocFlags(flags, new_size, type_name); + void* ret = no_hooks ? AllocFlagsNoHooks(flags, new_size, PartitionPageSize()) + : AllocFlagsInternal(flags, new_size, + PartitionPageSize(), type_name); if (!ret) { if (flags & PartitionAllocReturnNull) return nullptr;
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index 319d572d..a31b4be1 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -300,6 +300,16 @@ ALWAYS_INLINE void* AllocFlags(int flags, size_t requested_size, const char* type_name); + // Same as |AllocFlags()|, but allows specifying |slot_span_alignment|. It has + // to be a multiple of partition page size, greater than 0 and no greater than + // kMaxSupportedAlignment. If it equals exactly 1 partition page, no special + // action is taken as PartitoinAlloc naturally guarantees this alignment, + // otherwise a sub-optimial allocation strategy is used to guarantee the + // higher-order alignment. + ALWAYS_INLINE void* AllocFlagsInternal(int flags, + size_t requested_size, + size_t slot_span_alignment, + const char* type_name); // Same as |AllocFlags()|, but bypasses the allocator hooks. // // This is separate from AllocFlags() because other callers of AllocFlags() @@ -309,7 +319,9 @@ // taking the extra branch in the non-malloc() case doesn't hurt. In addition, // for the malloc() case, the compiler correctly removes the branch, since // this is marked |ALWAYS_INLINE|. - ALWAYS_INLINE void* AllocFlagsNoHooks(int flags, size_t requested_size); + ALWAYS_INLINE void* AllocFlagsNoHooks(int flags, + size_t requested_size, + size_t slot_span_alignment); ALWAYS_INLINE void* Realloc(void* ptr, size_t newize, const char* type_name); // Overload that may return nullptr if reallocation isn't possible. In this @@ -405,14 +417,8 @@ // limit before calling. This also guards against integer overflow in the // calculation here. PA_DCHECK(raw_size <= MaxDirectMapped()); - // Align to allocation granularity. However, in 64-bit mode, the granularity - // is super page size. - size_t alignment = PageAllocationGranularity(); -#if defined(PA_HAS_64_BITS_POINTERS) - alignment = kSuperPageSize; -#endif return bits::AlignUp(raw_size + GetDirectMapMetadataAndGuardPagesSize(), - alignment); + DirectMapAllocationGranularity()); } // PartitionRefCount contains a cookie if slow checks are enabled or @@ -562,11 +568,13 @@ ALWAYS_INLINE void* RawAlloc(Bucket* bucket, int flags, size_t raw_size, + size_t slot_span_alignment, size_t* usable_size, bool* is_already_zeroed); ALWAYS_INLINE void* AllocFromBucket(Bucket* bucket, int flags, size_t raw_size, + size_t slot_span_alignment, size_t* usable_size, bool* is_already_zeroed) EXCLUSIVE_LOCKS_REQUIRED(lock_); @@ -893,15 +901,22 @@ Bucket* bucket, int flags, size_t raw_size, + size_t slot_span_alignment, size_t* usable_size, bool* is_already_zeroed) { + PA_DCHECK(slot_span_alignment && + !(slot_span_alignment & PartitionPageOffsetMask())); SlotSpan* slot_span = bucket->active_slot_spans_head; // Check that this slot span is neither full nor freed. PA_DCHECK(slot_span); PA_DCHECK(slot_span->num_allocated_slots >= 0); void* slot_start = slot_span->freelist_head; - if (LIKELY(slot_start)) { + // Use the fast path when a slot is readily available on the free list of the + // first active slot span. However, fall back to the slow path if a + // higher-order alignment is requested, because an inner slot of an existing + // slot span is unlikely to satisfy it. + if (LIKELY(slot_span_alignment <= PartitionPageSize() && slot_start)) { *is_already_zeroed = false; // This is a fast path, so avoid calling GetUsableSize() on Release builds // as it is more costly. Copy its small bucket path instead. @@ -923,8 +938,8 @@ PA_DCHECK(slot_span->bucket == bucket); } else { - slot_start = - bucket->SlowPathAlloc(this, flags, raw_size, is_already_zeroed); + slot_start = bucket->SlowPathAlloc(this, flags, raw_size, + slot_span_alignment, is_already_zeroed); // TODO(palmer): See if we can afford to make this a CHECK. PA_DCHECK(!slot_start || IsValidSlotSpan(SlotSpan::FromSlotStartPtr(slot_start))); @@ -1276,6 +1291,19 @@ int flags, size_t requested_size, const char* type_name) { + return AllocFlagsInternal(flags, requested_size, PartitionPageSize(), + type_name); +} + +template <bool thread_safe> +ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocFlagsInternal( + int flags, + size_t requested_size, + size_t slot_span_alignment, + const char* type_name) { + PA_DCHECK(slot_span_alignment && + !(slot_span_alignment & PartitionPageOffsetMask())); + PA_DCHECK(flags < PartitionAllocLastFlag << 1); PA_DCHECK((flags & PartitionAllocNoHooks) == 0); // Internal only. PA_DCHECK(initialized); @@ -1299,7 +1327,7 @@ } } - ret = AllocFlagsNoHooks(flags, requested_size); + ret = AllocFlagsNoHooks(flags, requested_size, slot_span_alignment); if (UNLIKELY(hooks_enabled)) { PartitionAllocHooks::AllocationObserverHookIfEnabled(ret, requested_size, @@ -1313,7 +1341,11 @@ template <bool thread_safe> ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocFlagsNoHooks( int flags, - size_t requested_size) { + size_t requested_size, + size_t slot_span_alignment) { + PA_DCHECK(slot_span_alignment && + !(slot_span_alignment & PartitionPageOffsetMask())); + // The thread cache is added "in the middle" of the main allocator, that is: // - After all the cookie/ref-count management // - Before the "raw" allocator. @@ -1341,9 +1373,13 @@ // !thread_safe => !with_thread_cache, but adding the condition allows the // compiler to statically remove this branch for the thread-unsafe variant. // + // Don't use thread cache if higher order alignment is requested, because the + // thread cache will not be able to satisfy it. + // // LIKELY: performance-sensitive partitions are either thread-unsafe or use // the thread cache. - if (thread_safe && LIKELY(with_thread_cache)) { + if (thread_safe && + LIKELY(with_thread_cache && slot_span_alignment <= PartitionPageSize())) { auto* tcache = internal::ThreadCache::Get(); // LIKELY: Typically always true, except for the very first allocation of // this thread. @@ -1374,12 +1410,14 @@ PA_DCHECK(!slot_span->bucket->is_direct_mapped()); #endif } else { - slot_start = RawAlloc(buckets + bucket_index, flags, raw_size, - &usable_size, &is_already_zeroed); + slot_start = + RawAlloc(buckets + bucket_index, flags, raw_size, slot_span_alignment, + &usable_size, &is_already_zeroed); } } else { - slot_start = RawAlloc(buckets + bucket_index, flags, raw_size, &usable_size, - &is_already_zeroed); + slot_start = + RawAlloc(buckets + bucket_index, flags, raw_size, slot_span_alignment, + &usable_size, &is_already_zeroed); } if (UNLIKELY(!slot_start)) @@ -1483,11 +1521,12 @@ Bucket* bucket, int flags, size_t raw_size, + size_t slot_span_alignment, size_t* usable_size, bool* is_already_zeroed) { internal::ScopedGuard<thread_safe> guard{lock_}; - return AllocFromBucket(bucket, flags, raw_size, usable_size, - is_already_zeroed); + return AllocFromBucket(bucket, flags, raw_size, slot_span_alignment, + usable_size, is_already_zeroed); } template <bool thread_safe> @@ -1496,12 +1535,23 @@ size_t alignment, size_t requested_size) { // Aligned allocation support relies on the natural alignment guarantees of - // PartitionAlloc. Specifically, it relies on the fact that slot spans are - // partition-page aligned, and slots within are aligned to slot size, from - // the beginning of the span. As a conseqneuce, allocations of sizes that are - // a power of two, up to partition page size, will always be aligned to its - // size. The code below adjusts the request size to be a power of two. - // TODO(bartekn): Handle requests larger than partition page. + // PartitionAlloc. Specifically, it relies on the fact that slots within a + // slot span are aligned to slot size, from the beginning of the span. + // + // For alignments <=PartitionPageSize(), the code below adjusts the request + // size to be a power of two, no less than alignment. Since slot spans are + // aligned to PartitionPageSize(), which is also a power of two, this will + // automatically guarantee alignment on the adjusted size boundary, thanks to + // the natural alignment described above. + // + // For alignments >PartitionPageSize(), we need to pass the request down the + // stack to only give us a slot span aligned to this more restrictive + // boundary. In the current implementation, this code path will always + // allocate a new slot span and hand us the first slot, so no need to adjust + // the request size. As a consequence, allocating many small objects with + // such a high alignment can cause a non-negligable fragmentation, + // particularly if these allocations are back to back. + // TODO(bartekn): We should check that this is not causing issues in practice. // // Extras before the allocation are forbidden as they shift the returned // allocation from the beginning of the slot, thus messing up alignment. @@ -1511,40 +1561,51 @@ PA_DCHECK(!extras_offset); // This is mandated by |posix_memalign()|, so should never fire. PA_CHECK(base::bits::IsPowerOfTwo(alignment)); - + // Catch unsupported alignment requests early. + PA_CHECK(alignment <= kMaxSupportedAlignment); size_t raw_size = AdjustSizeForExtrasAdd(requested_size); - // Handle cases such as size = 16, alignment = 64. - // Wastes memory when a large alignment is requested with a small size, but - // this is hard to avoid, and should not be too common. - if (UNLIKELY(raw_size < alignment)) { - raw_size = alignment; - } else { - // PartitionAlloc only guarantees alignment for power-of-two sized - // allocations. To make sure this applies here, round up the allocation - // size. - raw_size = static_cast<size_t>(1) - << (sizeof(size_t) * 8 - - base::bits::CountLeadingZeroBits(raw_size - 1)); - } - PA_DCHECK(base::bits::IsPowerOfTwo(raw_size)); - // Adjust back, because AllocFlagsNoHooks/Alloc will adjust it again. - size_t adjusted_size = AdjustSizeForExtrasSubtract(raw_size); + // TODO(bartekn): Support direct map. Until then, catch unsupported requests. + PA_CHECK(alignment <= PartitionPageSize() || raw_size <= kMaxBucketed); - // Overflow check. adjusted_size must be larger or equal to requested_size. - if (UNLIKELY(adjusted_size < requested_size)) { - if (flags & PartitionAllocReturnNull) - return nullptr; - // OutOfMemoryDeathTest.AlignedAlloc requires - // base::TerminateBecauseOutOfMemory (invoked by - // PartitionExcessiveAllocationSize). - internal::PartitionExcessiveAllocationSize(requested_size); - // internal::PartitionExcessiveAllocationSize(size) causes OOM_CRASH. - NOTREACHED(); + size_t adjusted_size = requested_size; + if (alignment <= PartitionPageSize()) { + // Handle cases such as size = 16, alignment = 64. + // Wastes memory when a large alignment is requested with a small size, but + // this is hard to avoid, and should not be too common. + if (UNLIKELY(raw_size < alignment)) { + raw_size = alignment; + } else { + // PartitionAlloc only guarantees alignment for power-of-two sized + // allocations. To make sure this applies here, round up the allocation + // size. + raw_size = static_cast<size_t>(1) + << (sizeof(size_t) * 8 - + base::bits::CountLeadingZeroBits(raw_size - 1)); + } + PA_DCHECK(base::bits::IsPowerOfTwo(raw_size)); + // Adjust back, because AllocFlagsNoHooks/Alloc will adjust it again. + adjusted_size = AdjustSizeForExtrasSubtract(raw_size); + + // Overflow check. adjusted_size must be larger or equal to requested_size. + if (UNLIKELY(adjusted_size < requested_size)) { + if (flags & PartitionAllocReturnNull) + return nullptr; + // OutOfMemoryDeathTest.AlignedAlloc requires + // base::TerminateBecauseOutOfMemory (invoked by + // PartitionExcessiveAllocationSize). + internal::PartitionExcessiveAllocationSize(requested_size); + // internal::PartitionExcessiveAllocationSize(size) causes OOM_CRASH. + NOTREACHED(); + } } + // Slot spans are naturally aligned on partition page size, but make sure you + // don't pass anything less, because it'll mess up callee's calculations. + size_t slot_span_alignment = std::max(alignment, PartitionPageSize()); bool no_hooks = flags & PartitionAllocNoHooks; void* ptr = - no_hooks ? AllocFlagsNoHooks(0, adjusted_size) : Alloc(adjusted_size, ""); + no_hooks ? AllocFlagsNoHooks(0, adjusted_size, slot_span_alignment) + : AllocFlagsInternal(0, adjusted_size, slot_span_alignment, ""); // |alignment| is a power of two, but the compiler doesn't necessarily know // that. A regular % operation is very slow, make sure to use the equivalent,
diff --git a/base/allocator/partition_allocator/starscan/metadata_allocator.h b/base/allocator/partition_allocator/starscan/metadata_allocator.h index cc61db8..ed2d8ff 100644 --- a/base/allocator/partition_allocator/starscan/metadata_allocator.h +++ b/base/allocator/partition_allocator/starscan/metadata_allocator.h
@@ -5,6 +5,7 @@ #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_METADATA_ALLOCATOR_H_ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_STARSCAN_METADATA_ALLOCATOR_H_ +#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_root.h" namespace base { @@ -35,7 +36,7 @@ value_type* allocate(size_t size) { return static_cast<value_type*>(PCScanMetadataAllocator().AllocFlagsNoHooks( - 0, size * sizeof(value_type))); + 0, size * sizeof(value_type), PartitionPageSize())); } void deallocate(value_type* ptr, size_t size) { @@ -46,7 +47,8 @@ // Inherit from it to make a class allocated on the metadata partition. struct AllocatedOnPCScanMetadataPartition { static void* operator new(size_t size) { - return PCScanMetadataAllocator().AllocFlagsNoHooks(0, size); + return PCScanMetadataAllocator().AllocFlagsNoHooks(0, size, + PartitionPageSize()); } static void operator delete(void* ptr) { PCScanMetadataAllocator().FreeNoHooks(ptr); @@ -55,8 +57,8 @@ template <typename T, typename... Args> T* MakePCScanMetadata(Args&&... args) { - auto* memory = static_cast<T*>( - PCScanMetadataAllocator().AllocFlagsNoHooks(0, sizeof(T))); + auto* memory = static_cast<T*>(PCScanMetadataAllocator().AllocFlagsNoHooks( + 0, sizeof(T), PartitionPageSize())); return new (memory) T(std::forward<Args>(args)...); }
diff --git a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc index 4687768..82b0433 100644 --- a/base/allocator/partition_allocator/starscan/pcscan_unittest.cc +++ b/base/allocator/partition_allocator/starscan/pcscan_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_root.h" #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) @@ -44,10 +45,10 @@ // Previous test runs within the same process decommit GigaCage, therefore // we need to make sure that the card table is recommitted for each run. PCScan::ReinitForTesting(); - allocator_.init({PartitionOptions::AlignedAlloc::kDisallowed, + allocator_.init({PartitionOptions::AlignedAlloc::kAllowed, PartitionOptions::ThreadCache::kDisabled, PartitionOptions::Quarantine::kAllowed, - PartitionOptions::Cookies::kAllowed, + PartitionOptions::Cookies::kDisallowed, PartitionOptions::RefCount::kDisallowed}); PCScan::RegisterScannableRoot(allocator_.root()); } @@ -110,7 +111,7 @@ void* first = nullptr; void* last = nullptr; for (size_t i = 0; i < num_slots; ++i) { - void* ptr = root.AllocFlagsNoHooks(0, object_size); + void* ptr = root.AllocFlagsNoHooks(0, object_size, PartitionPageSize()); EXPECT_TRUE(ptr); if (i == 0) first = root.AdjustPointerForExtrasSubtract(ptr); @@ -148,12 +149,18 @@ ListBase* next = nullptr; }; -template <size_t Size> +template <size_t Size, size_t Alignment = 0> struct List final : ListBase { char buffer[Size]; static List* Create(ThreadSafePartitionRoot& root, ListBase* next = nullptr) { - auto* list = static_cast<List*>(root.Alloc(sizeof(List), nullptr)); + List* list; + if (Alignment) { + list = static_cast<List*>( + root.AlignedAllocFlags(0, Alignment, sizeof(List))); + } else { + list = static_cast<List*>(root.Alloc(sizeof(List), nullptr)); + } list->next = next; return list; } @@ -255,6 +262,52 @@ TestDanglingReference(*this, source, value); } +TEST_F(PCScanTest, DanglingReferenceDifferentBucketsAligned) { + // Choose a high alignment that almost certainly will cause a gap between slot + // spans. But make it less than kMaxSupportedAlignment, or else two + // allocations will end up on different super pages. + constexpr size_t alignment = kMaxSupportedAlignment / 2; + using SourceList = List<8, alignment>; + using ValueList = List<128, alignment>; + + // Create two objects, where |source| references |value|. + auto* value = ValueList::Create(root(), nullptr); + auto* source = SourceList::Create(root(), value); + + // Double check the setup -- make sure that exactly two slot spans were + // allocated, within the same super page, with a gap in between. + { + auto* value_root = ThreadSafePartitionRoot::FromPointerInNormalBuckets( + reinterpret_cast<char*>(value)); + ScopedGuard<ThreadSafe> guard{value_root->lock_}; + + auto super_page = reinterpret_cast<uintptr_t>(value) & kSuperPageBaseMask; + ASSERT_EQ(super_page, + reinterpret_cast<uintptr_t>(source) & kSuperPageBaseMask); + size_t i = 0; + void* first_slot_span_end = nullptr; + void* second_slot_span_start = nullptr; + auto visited = IterateSlotSpans<ThreadSafe>( + reinterpret_cast<char*>(super_page), true, + [&](SlotSpan* slot_span) -> bool { + if (i == 0) { + first_slot_span_end = reinterpret_cast<char*>( + SlotSpan::ToSlotSpanStartPtr(slot_span)) + + slot_span->bucket->get_pages_per_slot_span() * + PartitionPageSize(); + } else { + second_slot_span_start = SlotSpan::ToSlotSpanStartPtr(slot_span); + } + ++i; + return true; + }); + ASSERT_EQ(visited, 2u); + ASSERT_GT(second_slot_span_start, first_slot_span_end); + } + + TestDanglingReference(*this, source, value); +} + TEST_F(PCScanTest, DanglingReferenceSameSlotSpanButDifferentPages) { using SourceList = List<8>; using ValueList = SourceList; @@ -291,7 +344,8 @@ void* source_addr = full_slot_span.first; // This allocation must go through the slow path and call SetNewActivePage(), // which will flush the full page from the active page list. - void* value_addr = root().AllocFlagsNoHooks(0, sizeof(ValueList)); + void* value_addr = + root().AllocFlagsNoHooks(0, sizeof(ValueList), PartitionPageSize()); // Assert that the first and the last objects are in different slot spans but // in the same bucket.
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc index 011ec2e8..df069a8 100644 --- a/base/allocator/partition_allocator/thread_cache.cc +++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -10,6 +10,7 @@ #include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_config.h" +#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_root.h" #include "base/base_export.h" #include "base/dcheck_is_on.h" @@ -376,8 +377,9 @@ auto* bucket = root->buckets + PartitionRoot<internal::ThreadSafe>::SizeToBucketIndex(raw_size); - void* buffer = root->RawAlloc(bucket, PartitionAllocZeroFill, raw_size, - &usable_size, &already_zeroed); + void* buffer = + root->RawAlloc(bucket, PartitionAllocZeroFill, raw_size, + PartitionPageSize(), &usable_size, &already_zeroed); ThreadCache* tcache = new (buffer) ThreadCache(root); // This may allocate. @@ -503,8 +505,8 @@ void* ptr = root_->AllocFromBucket( &root_->buckets[bucket_index], PartitionAllocFastPathOrReturnNull | PartitionAllocReturnNull, - root_->buckets[bucket_index].slot_size /* raw_size */, &usable_size, - &is_already_zeroed); + root_->buckets[bucket_index].slot_size /* raw_size */, + PartitionPageSize(), &usable_size, &is_already_zeroed); // Either the previous allocation would require a slow path allocation, or // the central allocator is out of memory. If the bucket was filled with
diff --git a/base/memory/nonscannable_memory.cc b/base/memory/nonscannable_memory.cc index 35b627a4..81f730c 100644 --- a/base/memory/nonscannable_memory.cc +++ b/base/memory/nonscannable_memory.cc
@@ -30,10 +30,11 @@ // TODO(bikineev): Change to LIKELY once PCScan is enabled by default. if (UNLIKELY(pcscan_enabled_.load(std::memory_order_acquire))) { PA_DCHECK(allocator_.get()); - return allocator_->root()->AllocFlagsNoHooks(0, size); + return allocator_->root()->AllocFlagsNoHooks(0, size, PartitionPageSize()); } // Otherwise, dispatch to default partition. - return PartitionAllocMalloc::Allocator()->AllocFlagsNoHooks(0, size); + return PartitionAllocMalloc::Allocator()->AllocFlagsNoHooks( + 0, size, PartitionPageSize()); } void NonScannableAllocator::Free(void* ptr) {
diff --git a/base/optional.h b/base/optional.h index b105cc0..bdbbf9c2 100644 --- a/base/optional.h +++ b/base/optional.h
@@ -14,9 +14,9 @@ template <typename T> using Optional [[deprecated]] = absl::optional<T>; -using absl::make_optional [[deprecated]]; -using absl::nullopt [[deprecated]]; -using absl::nullopt_t [[deprecated]]; +using absl::make_optional; +using absl::nullopt; +using absl::nullopt_t; } // namespace base
diff --git a/build/config/linux/pangocairo/pangocairo.gni b/build/config/linux/pangocairo/pangocairo.gni index ecfe663..6bc7529 100644 --- a/build/config/linux/pangocairo/pangocairo.gni +++ b/build/config/linux/pangocairo/pangocairo.gni
@@ -6,8 +6,5 @@ import("//build/config/ui.gni") declare_args() { - use_pangocairo = - # TODO(crbug.com/1052397): Remove !chromeos_is_browser_only once - # lacros-chrome switches to target_os="chromeos" - is_linux && !is_chromecast && !chromeos_is_browser_only + use_pangocairo = is_linux && !is_chromecast }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 0519f7e..431de86 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -4.20210518.1.1 +4.20210518.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 0519f7e..431de86 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4.20210518.1.1 +4.20210518.2.1
diff --git a/chrome/VERSION b/chrome/VERSION index b7f1808..839e4665 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=92 MINOR=0 -BUILD=4512 +BUILD=4513 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 7065e7c..f8aa62f 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -20,6 +20,9 @@ import("//chrome/android/modules/chrome_feature_module_tmpl.gni") import("//chrome/android/monochrome_android_manifest_jinja_variables.gni") import("//chrome/browser/commerce/price_tracking/android/java_sources.gni") +import("//chrome/browser/commerce/subscriptions/android/java_sources.gni") +import( + "//chrome/browser/commerce/subscriptions/test/android/test_java_sources.gni") import("//chrome/browser/feed/android/web_feed_java_sources.gni") import("//chrome/browser/share/android/java_sources.gni") import("//chrome/chrome_paks.gni") @@ -313,7 +316,6 @@ "//chrome/browser/banners/android:java", "//chrome/browser/browser_controls/android:java", "//chrome/browser/commerce/merchant_viewer/android:java", - "//chrome/browser/commerce/subscriptions/android:java", "//chrome/browser/consent_auditor/android:java", "//chrome/browser/contextmenu:java", "//chrome/browser/continuous_search:data_structures_java", @@ -657,6 +659,11 @@ # dependency when circular deps is resolved. sources += price_tracking_java_sources + # TODO(crbug/1210158): Instead of adding source files, add it as a separate + # dependency when circular deps is resolved. + sources += commerce_subscriptions_java_sources + deps += commerce_subscriptions_java_deps + if (enable_basic_printing) { deps += [ "//printing:printing_java" ] } @@ -693,7 +700,6 @@ "//chrome/android/features/keyboard_accessory:internal_java", "//chrome/browser/attribution_reporting/android/internal:java", "//chrome/browser/commerce/merchant_viewer/android:java", - "//chrome/browser/commerce/subscriptions/android:java", "//chrome/browser/content_creation/notes/internal/android:java", "//chrome/browser/download/internal/android:java", "//chrome/browser/page_annotations/android:java", @@ -878,7 +884,6 @@ "//chrome/browser/browser_controls/android:java", "//chrome/browser/browser_controls/android:junit", "//chrome/browser/commerce/merchant_viewer/android:junit", - "//chrome/browser/commerce/subscriptions/test/android:junit", "//chrome/browser/contextmenu:java", "//chrome/browser/continuous_search:junit", "//chrome/browser/continuous_search/internal:junit", @@ -1174,7 +1179,6 @@ "//chrome/browser/banners/android:java", "//chrome/browser/browser_controls/android:java", "//chrome/browser/commerce/merchant_viewer/android:javatests", - "//chrome/browser/commerce/subscriptions/test/android:javatests", "//chrome/browser/contextmenu:java", "//chrome/browser/continuous_search:data_structures_java", "//chrome/browser/continuous_search:javatests", @@ -1440,6 +1444,8 @@ deps += feed_test_deps + deps += commerce_subscriptions_java_test_deps + if (enable_basic_printing) { deps += [ "//printing:printing_java" ] }
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/BLEAdvert.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/BLEAdvert.java index c5c08d9..b831009 100644 --- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/BLEAdvert.java +++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/BLEAdvert.java
@@ -49,27 +49,9 @@ .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) .build(); ParcelUuid fidoUuid = new ParcelUuid(UUID.fromString(CABLE_UUID)); - - // The first 16 bytes of the payload are encoded into a 16-byte UUID. - ByteBuffer bb = ByteBuffer.wrap(payload); - long high = bb.getLong(); - long low = bb.getLong(); - final UUID uuid16 = new UUID(high, low); - - // The final four bytes of the payload are turned into a 4-byte UUID. - // Depending on the value of those four bytes, this might happen to be a - // 2-byte UUID, but the desktop handles that. - high = (long) bb.getInt(); - high <<= 32; - // This is the fixed suffix for short UUIDs in Bluetooth. - high |= 0x1000; - low = 0x800000805f9b34fbL; - final UUID uuid4 = new UUID(high, low); - AdvertiseData data = (new AdvertiseData.Builder()) .addServiceUuid(fidoUuid) - .addServiceUuid(new ParcelUuid(uuid16)) - .addServiceUuid(new ParcelUuid(uuid4)) + .addServiceData(fidoUuid, payload) .setIncludeDeviceName(false) .setIncludeTxPowerLevel(false) .build();
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml index 6d87e0c..ee86ce4 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml +++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml
@@ -79,6 +79,12 @@ android:layout_height="wrap_content" style="@style/InputChip" /> + <org.chromium.ui.widget.ChipView + android:id="@+id/cvc" + android:gravity="center_vertical|start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/InputChip" /> </LinearLayout> <ImageView
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryInfoView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryInfoView.java index b7c84ae..e40bf6e7c 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryInfoView.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryInfoView.java
@@ -28,6 +28,7 @@ private ChipView mExpMonth; private ChipView mExpYear; private ChipView mCardholder; + private ChipView mCvc; /** * Constructor for inflating from XML. @@ -46,6 +47,7 @@ mExpMonth = findViewById(R.id.exp_month); mExpYear = findViewById(R.id.exp_year); mCardholder = findViewById(R.id.cardholder); + mCvc = findViewById(R.id.cvc); } public void setIcon(@Nullable Drawable drawable) { @@ -76,4 +78,8 @@ public LinearLayout getExpiryGroup() { return mExpiryGroup; } + + public ChipView getCvc() { + return mCvc; + } }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java index 53d16f8..81829847 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java
@@ -51,6 +51,7 @@ bindChipView(view.getExpMonth(), info.getFields().get(1)); bindChipView(view.getExpYear(), info.getFields().get(2)); bindChipView(view.getCardholder(), info.getFields().get(3)); + bindChipView(view.getCvc(), info.getFields().get(4)); view.getExpiryGroup().setVisibility(view.getExpYear().getVisibility() == View.VISIBLE || view.getExpMonth().getVisibility() == View.VISIBLE
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java index 91845693..f7323d58a 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java
@@ -196,6 +196,8 @@ new UserInfoField("2021", "2021", "-1", false, result -> {})); sheet.getUserInfoList().get(0).addField( new UserInfoField("Todd Tester", "Todd Tester", "0", false, result -> {})); + sheet.getUserInfoList().get(0).addField( + new UserInfoField("123", "123", "-1", false, result -> {})); sheet.getUserInfoList().add(new KeyboardAccessoryData.UserInfo("", false)); sheet.getUserInfoList().get(1).addField( new UserInfoField("**** 8012", "Card for Maya Park", "1", false, result -> {})); @@ -205,6 +207,8 @@ new UserInfoField("", "", "-1", false, result -> {})); sheet.getUserInfoList().get(1).addField( // Unused card holder field. new UserInfoField("", "", "1", false, result -> {})); + sheet.getUserInfoList().get(1).addField( + new UserInfoField("", "", "-1", false, result -> {})); sheet.getFooterCommands().add( new KeyboardAccessoryData.FooterCommand("Manage payment methods", cb -> {}));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java index d751f28..ae260f95 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
@@ -116,7 +116,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.add(new AccessorySheetDataPiece( - createInfo("4111111111111111", "04", "2034", "Kirby Puckett", clicked), + createInfo("4111111111111111", "04", "2034", "Kirby Puckett", "123", clicked), AccessorySheetDataPiece.Type.CREDIT_CARD_INFO)); mModel.add(new AccessorySheetDataPiece( new KeyboardAccessoryData.FooterCommand("Manage credit cards", null), @@ -151,6 +151,7 @@ infoWithUnclickableField.addField(new UserInfoField("", "", "month", false, null)); infoWithUnclickableField.addField(new UserInfoField("", "", "year", false, null)); infoWithUnclickableField.addField(new UserInfoField("", "", "name", false, null)); + infoWithUnclickableField.addField(new UserInfoField("", "", "cvc", false, null)); mModel.add(new AccessorySheetDataPiece( infoWithUnclickableField, AccessorySheetDataPiece.Type.CREDIT_CARD_INFO)); mModel.add(new AccessorySheetDataPiece( @@ -174,7 +175,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.add(new AccessorySheetDataPiece( // Cardholder name is empty - createInfo("4111111111111111", "04", "2034", "", clicked), + createInfo("4111111111111111", "04", "2034", "", "", clicked), AccessorySheetDataPiece.Type.CREDIT_CARD_INFO)); mModel.add(new AccessorySheetDataPiece( new KeyboardAccessoryData.FooterCommand("Manage credit cards", null), @@ -184,6 +185,7 @@ CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(2))); assertThat(findChipView(R.id.cardholder).isShown(), is(false)); + assertThat(findChipView(R.id.cvc).isShown(), is(false)); } @Test @@ -209,14 +211,15 @@ assertThat(warningText.getText(), is(kWarning)); } - private UserInfo createInfo( - String number, String month, String year, String name, AtomicBoolean clickRecorder) { + private UserInfo createInfo(String number, String month, String year, String name, String cvc, + AtomicBoolean clickRecorder) { UserInfo info = new UserInfo("", false); info.addField( new UserInfoField(number, number, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(month, month, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(year, year, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(name, name, "", false, item -> clickRecorder.set(true))); + info.addField(new UserInfoField(cvc, cvc, "", false, item -> clickRecorder.set(true))); return info; }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index 2527b08..c96235fb 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -1482,21 +1482,21 @@ // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/single/exclude_mv_tiles/false" + "/new_home_surface_from_home_button/hide_mv_tiles_and_tab_switcher"}) - @DisabledTest(message = "http://crbug/1206081 - the Instant_Return version is flaky.") public void testNewSurfaceFromHomeButton(){ // clang-format on - assumeTrue(mImmediateReturn); - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + if (mImmediateReturn) { + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - onViewWaiting( - allOf(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_container), isDisplayed())); - onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.carousel_tab_switcher_container)); - onViewWaiting(withId(R.id.start_tab_switcher_button)); + onViewWaiting( + allOf(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_layout), isDisplayed())); + onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.carousel_tab_switcher_container)); + onViewWaiting(withId(R.id.start_tab_switcher_button)); - // Launch a tab. The home button should show on the normal tab. - StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); + // Launch a tab. The home button should show on the normal tab. + StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); + } // Go back to the home surface, MV tiles and carousel tab switcher should not show anymore. StartSurfaceTestUtils.pressHomePageButton(cta); @@ -1519,18 +1519,19 @@ + "/new_home_surface_from_home_button/hide_tab_switcher_only"}) public void testNewSurfaceHideTabOnlyFromHomeButton() { // clang-format on - assumeTrue(mImmediateReturn); - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + if (mImmediateReturn) { + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_container)); - onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.carousel_tab_switcher_container)); - onViewWaiting(withId(R.id.start_tab_switcher_button)); + onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_layout)); + onViewWaiting(withId(org.chromium.chrome.tab_ui.R.id.carousel_tab_switcher_container)); + onViewWaiting(withId(R.id.start_tab_switcher_button)); - // Launch a tab. The home button should show on the normal tab. - StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); - onViewWaiting(withId(R.id.home_button)).check(matches(isDisplayed())); + // Launch a tab. The home button should show on the normal tab. + StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); + onViewWaiting(withId(R.id.home_button)).check(matches(isDisplayed())); + } // Go back to the home surface, MV tiles and carousel tab switcher should not show anymore. StartSurfaceTestUtils.pressHomePageButton(cta); @@ -1539,7 +1540,7 @@ StartSurfaceTestUtils.waitForOverviewVisible( mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); onViewWaiting(withId(R.id.start_tab_switcher_button)); - onView(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_container)) + onView(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_layout)) .check(matches(withEffectiveVisibility(VISIBLE))); onView(withId(org.chromium.chrome.tab_ui.R.id.carousel_tab_switcher_container)) .check(matches(withEffectiveVisibility(GONE))); @@ -1728,6 +1729,7 @@ @Feature({"StartSurface"}) @CommandLineFlags.Add({BASE_PARAMS + "/single"}) public void testOpenTileInIncognitoTabWithContextMenu() throws ExecutionException { + Assume.assumeFalse("https://crbug.com/1210554", mUseInstantStart && mImmediateReturn); if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java index c6d60c2..3d27db66 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -144,11 +144,15 @@ private class FeedSurfaceHeaderSelectedCallback implements OnSectionHeaderSelectedListener { @Override public void onSectionHeaderSelected(int index) { + PropertyListModel<PropertyModel, PropertyKey> headerList = + mSectionHeaderModel.get(SectionHeaderListProperties.SECTION_HEADERS_KEY); + if (index >= headerList.size()) { + Log.e(TAG, "Attempted to select a Tab with an invalid index"); + return; + } mSectionHeaderModel.set(SectionHeaderListProperties.CURRENT_TAB_INDEX_KEY, index); Runnable onSelectCallback = - mSectionHeaderModel.get(SectionHeaderListProperties.SECTION_HEADERS_KEY) - .get(index) - .get(SectionHeaderProperties.ON_SELECT_CALLBACK_KEY); + headerList.get(index).get(SectionHeaderProperties.ON_SELECT_CALLBACK_KEY); if (onSelectCallback != null) { onSelectCallback.run(); } @@ -1024,6 +1028,7 @@ private ScrollState getScrollStateForAutoScrollToTop() { ScrollState state = new ScrollState(); state.position = 1; + state.lastPosition = 5; return state; }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java index 65994f91..4b8519b9 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/FeedFeatures.java
@@ -42,7 +42,7 @@ public static boolean isAutoScrollToTopEnabled() { CommandLine commandLine = CommandLine.getInstance(); if (commandLine == null) return false; - return commandLine.hasSwitch("feed_auto_scroll_to_top"); + return commandLine.hasSwitch("feed-screenshot-mode"); } private static PrefService getPrefService() {
diff --git a/chrome/android/java/res/xml/search_widget_info.xml b/chrome/android/java/res/xml/search_widget_info.xml index d80b478..442092c5 100644 --- a/chrome/android/java/res/xml/search_widget_info.xml +++ b/chrome/android/java/res/xml/search_widget_info.xml
@@ -6,7 +6,7 @@ <!-- This widget automatically updates once per day, and whenever Chrome starts up. --> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" - android:minWidth="250dp" + android:minWidth="240dp" android:minHeight="48dp" android:initialLayout="@layout/search_widget_template" android:previewImage="@drawable/widget_preview"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderView.java index daf2d1cd..a6bd041 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderView.java
@@ -152,6 +152,13 @@ } } + /** Removes all tabs. */ + void removeAllTabs() { + if (mTabLayout != null) { + mTabLayout.removeAllTabs(); + } + } + /** * Set the properties for the header tab at a particular index to text. *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewBinder.java index 0f1325a..cfa92e6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SectionHeaderViewBinder.java
@@ -62,6 +62,11 @@ @Override public void onItemsRemoved(PropertyListModel<PropertyModel, PropertyKey> model, SectionHeaderView view, int index, int count) { + if (model.size() == 0) { + // All headers were removed. + view.removeAllTabs(); + return; + } for (int i = index + count - 1; i >= index; i--) { view.removeTabAt(i); }
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 5257d82..ee025118 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
@@ -63,6 +63,8 @@ import org.chromium.chrome.browser.signin.SyncConsentActivityLauncherImpl; import org.chromium.chrome.browser.signin.ui.SigninPromoUtil; import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator; +import org.chromium.chrome.browser.subscriptions.CommerceSubscriptionsService; +import org.chromium.chrome.browser.subscriptions.CommerceSubscriptionsServiceFactory; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabAssociatedApp; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -119,6 +121,7 @@ private HeightObserver mContinuousSearchObserver; private TabObscuringHandler.Observer mContinuousSearchTabObscuringHandlerObserver; private MerchantTrustSignalsCoordinator mMerchantTrustSignalsCoordinator; + private CommerceSubscriptionsService mCommerceSubscriptionsService; private int mStatusIndicatorHeight; private int mContinuousSearchHeight; @@ -232,6 +235,11 @@ mMerchantTrustSignalsCoordinator = null; } + if (mCommerceSubscriptionsService != null) { + mCommerceSubscriptionsService.destroy(); + mCommerceSubscriptionsService = null; + } + super.onDestroy(); } @@ -348,6 +356,7 @@ initContinuousSearchCoordinator(); initMerchantTrustSignals(); + initCommerceSubscriptionsService(); } private void initMerchantTrustSignals() { @@ -484,6 +493,17 @@ if (animate) browserControlsSizer.setAnimateBrowserControlsHeightChanges(false); } + private void initCommerceSubscriptionsService() { + if (!TabUiFeatureUtilities.ENABLE_PRICE_NOTIFICATION.getValue()) { + return; + } + + CommerceSubscriptionsServiceFactory factory = new CommerceSubscriptionsServiceFactory(); + mCommerceSubscriptionsService = factory.getForLastUsedProfile(); + mCommerceSubscriptionsService.initDeferredStartupForActivity( + mActivity.getTabModelSelector(), mActivity.getLifecycleDispatcher()); + } + private void initStatusIndicatorCoordinator(LayoutManagerImpl layoutManager) { // TODO(crbug.com/1035584): Disable on tablets for now as we need to do one or two extra // things for tablets.
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 7979c798..5d622d4 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -14,6 +14,8 @@ import("//chrome/android/features/tab_ui/tab_management_java_sources.gni") import("//chrome/android/feed/feed_java_sources.gni") import("//chrome/browser/commerce/price_tracking/android/test_java_sources.gni") +import( + "//chrome/browser/commerce/subscriptions/test/android/test_java_sources.gni") import("//chrome/browser/feed/android/web_feed_java_sources.gni") import("//chrome/browser/share/android/test_java_sources.gni") import("//chrome/common/features.gni") @@ -46,6 +48,9 @@ chrome_junit_test_java_sources += share_junit_test_java_sources chrome_junit_test_java_deps = share_junit_test_java_deps chrome_junit_test_java_deps += feed_test_deps +chrome_junit_test_java_sources += commerce_subscriptions_junit_test_sources +chrome_junit_test_java_deps += commerce_subscriptions_junit_test_deps +chrome_test_java_sources += commerce_subscriptions_java_test_sources if (enable_arcore) { chrome_java_sources += [
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogTest.java index 05e80a5..2180c5d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogTest.java
@@ -6,13 +6,14 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.Visibility.GONE; import static androidx.test.espresso.matcher.ViewMatchers.isChecked; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked; +import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -129,6 +130,10 @@ when(mPrefService.getInteger(Pref.PROMPT_FOR_DOWNLOAD_ANDROID)).thenReturn(promptStatus); } + private void setPromptForPolicy(boolean promptForPolicy) { + when(mPrefService.getBoolean(Pref.PROMPT_FOR_DOWNLOAD)).thenReturn(promptForPolicy); + } + private void showDialog( long totalBytes, @DownloadLocationDialogType int dialogType, String suggestedPath) { TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -152,7 +157,7 @@ */ private void assertDontShowAgainCheckbox(Boolean checked) { if (checked == null) { - onView(withId(R.id.show_again_checkbox)).check(matches(not(isDisplayed()))); + onView(withId(R.id.show_again_checkbox)).check(matches(withEffectiveVisibility(GONE))); } else if (checked) { onView(withId(R.id.show_again_checkbox)).check(matches(isChecked())); } else { @@ -178,4 +183,16 @@ assertSubtitle(DownloadUtils.getStringForBytes(getActivity(), TOTAL_BYTES)); assertDontShowAgainCheckbox(false); } + + @Test + @MediumTest + public void testForceShowEnterprisePolicy() { + when(mDownloadDialogBridgeJniMock.isLocationDialogManaged()).thenReturn(true); + setPromptForPolicy(true); + setDownloadPromptStatus(DownloadPromptStatus.SHOW_PREFERENCE); + showDialog(TOTAL_BYTES, DownloadLocationDialogType.DEFAULT, SUGGESTED_PATH); + assertTitle(R.string.download_location_dialog_title_confirm_download); + assertSubtitle(DownloadUtils.getStringForBytes(getActivity(), TOTAL_BYTES)); + assertDontShowAgainCheckbox(null); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java index 9863831..92140415b6 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java
@@ -37,6 +37,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.robolectric.shadows.ShadowLog; import org.chromium.base.Callback; @@ -75,6 +76,8 @@ /** Unit tests for {@link FeedStream}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = {ShadowPostTask.class, ShadowRecordHistogram.class}) +// TODO(crbug.com/1210371): Rewrite using paused loop. See crbug for details. +@LooperMode(LooperMode.Mode.LEGACY) public class FeedStreamTest { private static final int LOAD_MORE_TRIGGER_LOOKAHEAD = 5; private static final int LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP = 100;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 88ba7c2..f5af4c8 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -354,6 +354,9 @@ <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_LOADING" desc="Label informing the user that the activation code is currently being verified."> Verifying activation code... </message> + <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_VERIFYING_ACTIVATION_CODE" desc="Label informing the user that the activation code is currently being verified, and that it may take a couple of minutes before it is complete."> + Verifying activation code. This may take a few minutes. + </message> <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID" desc="Label informing the user that the code used to install an eSIM profile is invalid."> Invalid code. Please try again. </message> @@ -6036,4 +6039,9 @@ </message> </if> + <!-- Strings for Projector--> + <message name="IDS_SELFIE_CAM_TITLE" desc="The title for the selfie camera dialog."> + Selfie Camera + </message> + </grit-part>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PAGE_VERIFYING_ACTIVATION_CODE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PAGE_VERIFYING_ACTIVATION_CODE.png.sha1 new file mode 100644 index 0000000..525e00b --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_ESIM_PAGE_VERIFYING_ACTIVATION_CODE.png.sha1
@@ -0,0 +1 @@ +b25b3277abcc39376632b9a832d89d3cbf826a53 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SELFIE_CAM_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SELFIE_CAM_TITLE.png.sha1 new file mode 100644 index 0000000..70c7e97 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_SELFIE_CAM_TITLE.png.sha1
@@ -0,0 +1 @@ +ca965f8892632fdb05f1abd84dbb29716c814e7d \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 497e9053..1f5d7c3a 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2087,6 +2087,7 @@ "//components/language/core/common", "//components/lens", "//components/leveldb_proto", + "//components/live_caption:constants", "//components/lookalikes/core", "//components/lookalikes/core:features", "//components/metrics:call_stack_profile_collector", @@ -3399,10 +3400,10 @@ "accessibility/caption_controller.h", "accessibility/caption_controller_factory.cc", "accessibility/caption_controller_factory.h", - "accessibility/caption_host_impl.cc", - "accessibility/caption_host_impl.h", "accessibility/invert_bubble_prefs.cc", "accessibility/invert_bubble_prefs.h", + "accessibility/live_caption_speech_recognition_host.cc", + "accessibility/live_caption_speech_recognition_host.h", "apps/app_service/app_icon_factory.cc", "apps/app_service/app_icon_factory.h", "apps/app_service/app_icon_source.cc", @@ -3583,10 +3584,14 @@ "enterprise/connectors/connectors_service.h", "enterprise/connectors/device_trust/attestation_service.cc", "enterprise/connectors/device_trust/attestation_service.h", + "enterprise/connectors/device_trust/crypto_utility.cc", + "enterprise/connectors/device_trust/crypto_utility.h", "enterprise/connectors/device_trust/device_trust_factory.cc", "enterprise/connectors/device_trust/device_trust_factory.h", "enterprise/connectors/device_trust/device_trust_service.cc", "enterprise/connectors/device_trust/device_trust_service.h", + "enterprise/connectors/device_trust/google_keys.cc", + "enterprise/connectors/device_trust/google_keys.h", "enterprise/connectors/device_trust/signal_reporter.cc", "enterprise/connectors/device_trust/signal_reporter.h", "enterprise/connectors/enterprise_connectors_policy_handler.cc", @@ -4240,7 +4245,6 @@ "//components/feedback/content:factory", "//components/image_fetcher/core", "//components/keep_alive_registry", - "//components/live_caption:constants", "//components/pref_registry", "//components/services/app_service:lib", "//components/services/app_service/public/cpp:app_file_handling",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 96578742..f802a123 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -6261,9 +6261,6 @@ #endif // !defined(OS_ANDROID) #if defined(OS_ANDROID) - {"page-info-version-2", flag_descriptions::kPageInfoV2Name, - flag_descriptions::kPageInfoV2Description, kOsAndroid, - FEATURE_VALUE_TYPE(page_info::kPageInfoV2)}, {"page-info-discoverability", flag_descriptions::kPageInfoDiscoverabilityName, flag_descriptions::kPageInfoDiscoverabilityDescription, kOsAndroid, @@ -6697,8 +6694,9 @@ flag_descriptions::kSyncAutofillWalletOfferDataDescription, kOsAll, FEATURE_VALUE_TYPE(switches::kSyncAutofillWalletOfferData)}, -#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ - defined(OS_CHROMEOS) +#if (defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ + defined(OS_CHROMEOS)) && \ + BUILDFLAG(ENABLE_PRINTING) {"enable-oop-print-drivers", flag_descriptions::kEnableOopPrintDriversName, flag_descriptions::kEnableOopPrintDriversDescription, kOsDesktop, FEATURE_VALUE_TYPE(printing::features::kEnableOopPrintDrivers)},
diff --git a/chrome/browser/accessibility/caption_controller.cc b/chrome/browser/accessibility/caption_controller.cc index 4398214d..5c9c839 100644 --- a/chrome/browser/accessibility/caption_controller.cc +++ b/chrome/browser/accessibility/caption_controller.cc
@@ -9,8 +9,8 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/metrics/histogram_functions.h" -#include "chrome/browser/accessibility/caption_host_impl.h" #include "chrome/browser/accessibility/caption_util.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/caption_bubble_controller.h" #include "chrome/common/pref_names.h" @@ -213,23 +213,27 @@ } bool CaptionController::DispatchTranscription( - CaptionHostImpl* caption_host_impl, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result) { if (!caption_bubble_controller_) return false; - return caption_bubble_controller_->OnTranscription(caption_host_impl, result); + return caption_bubble_controller_->OnTranscription( + live_caption_speech_recognition_host, result); } -void CaptionController::OnError(CaptionHostImpl* caption_host_impl) { +void CaptionController::OnError( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_controller_) return; - caption_bubble_controller_->OnError(caption_host_impl); + caption_bubble_controller_->OnError(live_caption_speech_recognition_host); } -void CaptionController::OnAudioStreamEnd(CaptionHostImpl* caption_host_impl) { +void CaptionController::OnAudioStreamEnd( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_controller_) return; - caption_bubble_controller_->OnAudioStreamEnd(caption_host_impl); + caption_bubble_controller_->OnAudioStreamEnd( + live_caption_speech_recognition_host); } void CaptionController::OnLanguageIdentificationEvent(
diff --git a/chrome/browser/accessibility/caption_controller.h b/chrome/browser/accessibility/caption_controller.h index 6afbc50..e0cd6c6 100644 --- a/chrome/browser/accessibility/caption_controller.h +++ b/chrome/browser/accessibility/caption_controller.h
@@ -28,7 +28,7 @@ namespace captions { class CaptionBubbleController; -class CaptionHostImpl; +class LiveCaptionSpeechRecognitionHost; /////////////////////////////////////////////////////////////////////////////// // Caption Controller @@ -56,7 +56,7 @@ // transcription result was routed successfully. Transcriptions will halt if // this returns false. bool DispatchTranscription( - CaptionHostImpl* caption_host_impl, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result); void OnLanguageIdentificationEvent( @@ -64,10 +64,12 @@ // Alerts the CaptionBubbleController that there is an error in the speech // recognition service. - void OnError(CaptionHostImpl* caption_host_impl); + void OnError( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host); // Alerts the CaptionBubbleController that the audio stream has ended. - void OnAudioStreamEnd(CaptionHostImpl* caption_host_impl); + void OnAudioStreamEnd( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host); private: friend class CaptionControllerFactory;
diff --git a/chrome/browser/accessibility/caption_controller_browsertest.cc b/chrome/browser/accessibility/caption_controller_browsertest.cc index b65a8bb..b434f95 100644 --- a/chrome/browser/accessibility/caption_controller_browsertest.cc +++ b/chrome/browser/accessibility/caption_controller_browsertest.cc
@@ -11,7 +11,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/accessibility/caption_controller_factory.h" -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/browser_features.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -110,12 +110,13 @@ return GetControllerForProfile(profile)->caption_bubble_controller_.get(); } - CaptionHostImpl* GetCaptionHostImpl() { - if (!caption_host_impl_) { - caption_host_impl_ = std::make_unique<CaptionHostImpl>( + LiveCaptionSpeechRecognitionHost* GetLiveCaptionSpeechRecognitionHost() { + if (!live_caption_speech_recognition_host_) { + live_caption_speech_recognition_host_ = std::make_unique< + LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame()); } - return caption_host_impl_.get(); + return live_caption_speech_recognition_host_.get(); } bool DispatchTranscription(std::string text) { @@ -124,20 +125,22 @@ bool DispatchTranscriptionToProfile(std::string text, Profile* profile) { return GetControllerForProfile(profile)->DispatchTranscription( - GetCaptionHostImpl(), + GetLiveCaptionSpeechRecognitionHost(), media::mojom::SpeechRecognitionResult::New(text, false /* is_final */)); } void OnError() { OnErrorOnProfile(browser()->profile()); } void OnErrorOnProfile(Profile* profile) { - GetControllerForProfile(profile)->OnError(GetCaptionHostImpl()); + GetControllerForProfile(profile)->OnError( + GetLiveCaptionSpeechRecognitionHost()); } void OnAudioStreamEnd() { OnAudioStreamEndOnProfile(browser()->profile()); } void OnAudioStreamEndOnProfile(Profile* profile) { - GetControllerForProfile(profile)->OnAudioStreamEnd(GetCaptionHostImpl()); + GetControllerForProfile(profile)->OnAudioStreamEnd( + GetLiveCaptionSpeechRecognitionHost()); } bool HasBubbleController() { @@ -177,7 +180,8 @@ private: base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<CaptionHostImpl> caption_host_impl_; + std::unique_ptr<LiveCaptionSpeechRecognitionHost> + live_caption_speech_recognition_host_; }; IN_PROC_BROWSER_TEST_F(CaptionControllerTest, ProfilePrefsAreRegistered) {
diff --git a/chrome/browser/accessibility/caption_host_impl.cc b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc similarity index 71% rename from chrome/browser/accessibility/caption_host_impl.cc rename to chrome/browser/accessibility/live_caption_speech_recognition_host.cc index c050d1a..a488705 100644 --- a/chrome/browser/accessibility/caption_host_impl.cc +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include <memory> #include <utility> @@ -17,15 +17,17 @@ namespace captions { // static -void CaptionHostImpl::Create( +void LiveCaptionSpeechRecognitionHost::Create( content::RenderFrameHost* frame_host, mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient> receiver) { - mojo::MakeSelfOwnedReceiver(std::make_unique<CaptionHostImpl>(frame_host), - std::move(receiver)); + mojo::MakeSelfOwnedReceiver( + std::make_unique<LiveCaptionSpeechRecognitionHost>(frame_host), + std::move(receiver)); } -CaptionHostImpl::CaptionHostImpl(content::RenderFrameHost* frame_host) +LiveCaptionSpeechRecognitionHost::LiveCaptionSpeechRecognitionHost( + content::RenderFrameHost* frame_host) : frame_host_(frame_host) { content::WebContents* web_contents = GetWebContents(); if (!web_contents) @@ -33,13 +35,13 @@ Observe(web_contents); } -CaptionHostImpl::~CaptionHostImpl() { +LiveCaptionSpeechRecognitionHost::~LiveCaptionSpeechRecognitionHost() { CaptionController* caption_controller = GetCaptionController(); if (caption_controller) caption_controller->OnAudioStreamEnd(this); } -void CaptionHostImpl::OnSpeechRecognitionRecognitionEvent( +void LiveCaptionSpeechRecognitionHost::OnSpeechRecognitionRecognitionEvent( media::mojom::SpeechRecognitionResultPtr result, OnSpeechRecognitionRecognitionEventCallback reply) { CaptionController* caption_controller = GetCaptionController(); @@ -50,7 +52,7 @@ std::move(reply).Run(caption_controller->DispatchTranscription(this, result)); } -void CaptionHostImpl::OnLanguageIdentificationEvent( +void LiveCaptionSpeechRecognitionHost::OnLanguageIdentificationEvent( media::mojom::LanguageIdentificationEventPtr event) { CaptionController* caption_controller = GetCaptionController(); if (!caption_controller) @@ -59,18 +61,19 @@ caption_controller->OnLanguageIdentificationEvent(std::move(event)); } -void CaptionHostImpl::OnSpeechRecognitionError() { +void LiveCaptionSpeechRecognitionHost::OnSpeechRecognitionError() { CaptionController* caption_controller = GetCaptionController(); if (caption_controller) caption_controller->OnError(this); } -void CaptionHostImpl::RenderFrameDeleted(content::RenderFrameHost* frame_host) { +void LiveCaptionSpeechRecognitionHost::RenderFrameDeleted( + content::RenderFrameHost* frame_host) { if (frame_host == frame_host_) frame_host_ = nullptr; } -content::WebContents* CaptionHostImpl::GetWebContents() { +content::WebContents* LiveCaptionSpeechRecognitionHost::GetWebContents() { if (!frame_host_) return nullptr; content::WebContents* web_contents = @@ -80,7 +83,7 @@ return web_contents; } -CaptionController* CaptionHostImpl::GetCaptionController() { +CaptionController* LiveCaptionSpeechRecognitionHost::GetCaptionController() { content::WebContents* web_contents = GetWebContents(); if (!web_contents) return nullptr;
diff --git a/chrome/browser/accessibility/caption_host_impl.h b/chrome/browser/accessibility/live_caption_speech_recognition_host.h similarity index 65% rename from chrome/browser/accessibility/caption_host_impl.h rename to chrome/browser/accessibility/live_caption_speech_recognition_host.h index a105a34..dcc3e06 100644 --- a/chrome/browser/accessibility/caption_host_impl.h +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ACCESSIBILITY_CAPTION_HOST_IMPL_H_ -#define CHROME_BROWSER_ACCESSIBILITY_CAPTION_HOST_IMPL_H_ +#ifndef CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SPEECH_RECOGNITION_HOST_H_ +#define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SPEECH_RECOGNITION_HOST_H_ #include "content/public/browser/web_contents_observer.h" #include "media/mojo/mojom/speech_recognition_service.mojom.h" @@ -18,19 +18,23 @@ class CaptionController; /////////////////////////////////////////////////////////////////////////////// -// Caption Host Impl +// Live Caption Speech Recognition Host // // A class that implements the Mojo interface -// SpeechRecognitionRecognizerClient. There exists one CaptionHostImpl per -// render frame. +// SpeechRecognitionRecognizerClient. There exists one +// LiveCaptionSpeechRecognitionHost per render frame. // -class CaptionHostImpl : public media::mojom::SpeechRecognitionRecognizerClient, - public content::WebContentsObserver { +class LiveCaptionSpeechRecognitionHost + : public media::mojom::SpeechRecognitionRecognizerClient, + public content::WebContentsObserver { public: - explicit CaptionHostImpl(content::RenderFrameHost* frame_host); - CaptionHostImpl(const CaptionHostImpl&) = delete; - CaptionHostImpl& operator=(const CaptionHostImpl&) = delete; - ~CaptionHostImpl() override; + explicit LiveCaptionSpeechRecognitionHost( + content::RenderFrameHost* frame_host); + LiveCaptionSpeechRecognitionHost(const LiveCaptionSpeechRecognitionHost&) = + delete; + LiveCaptionSpeechRecognitionHost& operator=( + const LiveCaptionSpeechRecognitionHost&) = delete; + ~LiveCaptionSpeechRecognitionHost() override; // static static void Create( @@ -64,4 +68,4 @@ } // namespace captions -#endif // CHROME_BROWSER_ACCESSIBILITY_CAPTION_HOST_IMPL_H_ +#endif // CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SPEECH_RECOGNITION_HOST_H_
diff --git a/chrome/browser/accessibility/caption_host_impl_browsertest.cc b/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc similarity index 78% rename from chrome/browser/accessibility/caption_host_impl_browsertest.cc rename to chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc index 293ce54..029deeb 100644 --- a/chrome/browser/accessibility/caption_host_impl_browsertest.cc +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" @@ -36,12 +36,14 @@ namespace captions { -class CaptionHostImplTest : public InProcessBrowserTest { +class LiveCaptionSpeechRecognitionHostTest : public InProcessBrowserTest { public: - CaptionHostImplTest() = default; - ~CaptionHostImplTest() override = default; - CaptionHostImplTest(const CaptionHostImplTest&) = delete; - CaptionHostImplTest& operator=(const CaptionHostImplTest&) = delete; + LiveCaptionSpeechRecognitionHostTest() = default; + ~LiveCaptionSpeechRecognitionHostTest() override = default; + LiveCaptionSpeechRecognitionHostTest( + const LiveCaptionSpeechRecognitionHostTest&) = delete; + LiveCaptionSpeechRecognitionHostTest& operator=( + const LiveCaptionSpeechRecognitionHostTest&) = delete; // InProcessBrowserTest overrides: void SetUp() override { @@ -49,12 +51,13 @@ InProcessBrowserTest::SetUp(); } - void CreateCaptionHostImpl(content::RenderFrameHost* frame_host) { + void CreateLiveCaptionSpeechRecognitionHost( + content::RenderFrameHost* frame_host) { mojo::Remote<media::mojom::SpeechRecognitionRecognizerClient> remote; mojo::PendingReceiver<media::mojom::SpeechRecognitionRecognizerClient> receiver; remote.Bind(receiver.InitWithNewPipeAndPassRemote()); - CaptionHostImpl::Create(frame_host, std::move(receiver)); + LiveCaptionSpeechRecognitionHost::Create(frame_host, std::move(receiver)); remotes_.emplace(frame_host, std::move(remote)); } @@ -63,7 +66,8 @@ bool expected_success) { remotes_[frame_host]->OnSpeechRecognitionRecognitionEvent( media::mojom::SpeechRecognitionResult::New(text, /*final=*/true), - base::BindOnce(&CaptionHostImplTest::DispatchTranscriptionCallback, + base::BindOnce(&LiveCaptionSpeechRecognitionHostTest:: + DispatchTranscriptionCallback, base::Unretained(this), expected_success)); } @@ -98,10 +102,11 @@ remotes_; }; -IN_PROC_BROWSER_TEST_F(CaptionHostImplTest, DestroysWithoutCrashing) { +IN_PROC_BROWSER_TEST_F(LiveCaptionSpeechRecognitionHostTest, + DestroysWithoutCrashing) { content::RenderFrameHost* frame_host = browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); - CreateCaptionHostImpl(frame_host); + CreateLiveCaptionSpeechRecognitionHost(frame_host); SetLiveCaptionEnabled(true); OnSpeechRecognitionRecognitionEvent( @@ -120,11 +125,11 @@ base::RunLoop().RunUntilIdle(); } -IN_PROC_BROWSER_TEST_F(CaptionHostImplTest, +IN_PROC_BROWSER_TEST_F(LiveCaptionSpeechRecognitionHostTest, OnSpeechRecognitionRecognitionEvent) { content::RenderFrameHost* frame_host = browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); - CreateCaptionHostImpl(frame_host); + CreateLiveCaptionSpeechRecognitionHost(frame_host); SetLiveCaptionEnabled(true); OnSpeechRecognitionRecognitionEvent(frame_host, @@ -140,20 +145,22 @@ base::RunLoop().RunUntilIdle(); } -IN_PROC_BROWSER_TEST_F(CaptionHostImplTest, OnLanguageIdentificationEvent) { +IN_PROC_BROWSER_TEST_F(LiveCaptionSpeechRecognitionHostTest, + OnLanguageIdentificationEvent) { content::RenderFrameHost* frame_host = browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); - CreateCaptionHostImpl(frame_host); + CreateLiveCaptionSpeechRecognitionHost(frame_host); SetLiveCaptionEnabled(true); OnLanguageIdentificationEvent( frame_host, "en-US", media::mojom::ConfidenceLevel::kHighlyConfident); } -IN_PROC_BROWSER_TEST_F(CaptionHostImplTest, OnSpeechRecognitionError) { +IN_PROC_BROWSER_TEST_F(LiveCaptionSpeechRecognitionHostTest, + OnSpeechRecognitionError) { content::RenderFrameHost* frame_host = browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); - CreateCaptionHostImpl(frame_host); + CreateLiveCaptionSpeechRecognitionHost(frame_host); SetLiveCaptionEnabled(true); OnSpeechRecognitionError(frame_host);
diff --git a/chrome/browser/apps/app_service/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon_factory.cc index 08d3f21d..9ece50f 100644 --- a/chrome/browser/apps/app_service/app_icon_factory.cc +++ b/chrome/browser/apps/app_service/app_icon_factory.cc
@@ -333,6 +333,50 @@ return absl::nullopt; } +#if BUILDFLAG(IS_CHROMEOS_ASH) +apps::mojom::IconValuePtr ApplyEffects(apps::IconEffects icon_effects, + int size_hint_in_dip, + apps::mojom::IconValuePtr iv, + gfx::ImageSkia mask_image) { + base::AssertLongCPUWorkAllowed(); + + extensions::ChromeAppIcon::ResizeFunction resize_function; + if (icon_effects & apps::IconEffects::kResizeAndPad) { + // TODO(crbug.com/826982): MD post-processing is not always applied: "See + // legacy code: + // https://cs.chromium.org/search/?q=ChromeAppIconLoader&type=cs In one + // cases MD design is used in another not." + resize_function = + base::BindRepeating(&app_list::MaybeResizeAndPadIconForMd); + } + + if ((icon_effects & apps::IconEffects::kCrOsStandardMask) && + !mask_image.isNull()) { + if (icon_effects & apps::IconEffects::kCrOsStandardBackground) { + iv->uncompressed = gfx::ImageSkiaOperations::CreateButtonBackground( + SK_ColorWHITE, iv->uncompressed, mask_image); + } else { + iv->uncompressed = gfx::ImageSkiaOperations::CreateMaskedImage( + iv->uncompressed, mask_image); + } + } + + if (icon_effects & apps::IconEffects::kCrOsStandardIcon) { + iv->uncompressed = apps::CreateStandardIconImage(iv->uncompressed); + } + + if (!resize_function.is_null()) { + resize_function.Run(gfx::Size(size_hint_in_dip, size_hint_in_dip), + &iv->uncompressed); + } + + if (!iv->uncompressed.isNull()) + iv->uncompressed.MakeThreadSafe(); + + return iv; +} +#endif + // This pipeline is meant to: // * Simplify loading icons, as things like effects and type are common // to all loading. @@ -393,6 +437,16 @@ callback) : arc_activity_icons_callback_(std::move(callback)) {} + IconLoadingPipeline(int size_hint_in_dip, + apps::mojom::Publisher::LoadIconCallback callback) + : size_hint_in_dip_(size_hint_in_dip), callback_(std::move(callback)) {} + + void ApplyIconEffects(apps::IconEffects icon_effects, + apps::mojom::IconValuePtr iv); + + void ApplyBadges(apps::IconEffects icon_effects, + apps::mojom::IconValuePtr iv); + void LoadWebAppIcon(const std::string& web_app_id, const GURL& launch_url, const web_app::AppIconManager& icon_manager, @@ -456,7 +510,9 @@ void CompleteWithCompressed(std::vector<uint8_t> data); - void CompleteWithImageSkia(gfx::ImageSkia image); + void CompleteWithUncompressed(apps::mojom::IconValuePtr iv); + + void CompleteWithIconValue(apps::mojom::IconValuePtr iv); void OnReadWebAppIcon(std::map<int, SkBitmap> icon_bitmaps); @@ -495,6 +551,10 @@ base::CancelableTaskTracker cancelable_task_tracker_; + // A sequenced task runner to create standard icons and not spamming the + // thread pool. + scoped_refptr<base::SequencedTaskRunner> standard_icon_task_runner_; + gfx::ImageSkia foreground_image_; gfx::ImageSkia background_image_; bool foreground_is_set_ = false; @@ -513,6 +573,65 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) }; +void IconLoadingPipeline::ApplyIconEffects(apps::IconEffects icon_effects, + apps::mojom::IconValuePtr iv) { + if (!iv || iv->uncompressed.isNull()) + return; + +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (!standard_icon_task_runner_) { + standard_icon_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( + {base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); + } + + gfx::ImageSkia mask_image; + if (icon_effects & apps::IconEffects::kCrOsStandardMask) { + mask_image = apps::LoadMaskImage(GetScaleToSize(iv->uncompressed)); + mask_image.MakeThreadSafe(); + } + + iv->uncompressed.MakeThreadSafe(); + + base::PostTaskAndReplyWithResult( + standard_icon_task_runner_.get(), FROM_HERE, + base::BindOnce(&ApplyEffects, icon_effects, size_hint_in_dip_, + std::move(iv), mask_image), + base::BindOnce(&IconLoadingPipeline::ApplyBadges, + base::WrapRefCounted(this), icon_effects)); +#else + ApplyBadges(icon_effects, std::move(iv)); +#endif +} + +void IconLoadingPipeline::ApplyBadges(apps::IconEffects icon_effects, + apps::mojom::IconValuePtr iv) { + const bool from_bookmark = icon_effects & apps::IconEffects::kRoundCorners; + + bool app_launchable = true; + // Only one badge can be visible at a time. + // Priority in which badges are applied (from the highest): Blocked > Paused > + // Chrome. This means than when apps are disabled or paused app type + // distinction information (Chrome vs Android) is lost. + extensions::ChromeAppIcon::Badge badge_type = + extensions::ChromeAppIcon::Badge::kNone; + if (icon_effects & apps::IconEffects::kBlocked) { + badge_type = extensions::ChromeAppIcon::Badge::kBlocked; + app_launchable = false; + } else if (icon_effects & apps::IconEffects::kPaused) { + badge_type = extensions::ChromeAppIcon::Badge::kPaused; + app_launchable = false; + } else if (icon_effects & apps::IconEffects::kChromeBadge) { + badge_type = extensions::ChromeAppIcon::Badge::kChrome; + } + + extensions::ChromeAppIcon::ApplyEffects( + size_hint_in_dip_, extensions::ChromeAppIcon::ResizeFunction(), + app_launchable, from_bookmark, badge_type, &iv->uncompressed); + + std::move(callback_).Run(std::move(iv)); +} + void IconLoadingPipeline::LoadWebAppIcon( const std::string& web_app_id, const GURL& launch_url, @@ -885,28 +1004,24 @@ MaybeLoadFallbackOrCompleteEmpty(); return; } - gfx::ImageSkia processed_image = image; + + apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); + iv->icon_type = icon_type_; + iv->uncompressed = image; + iv->is_placeholder_icon = is_placeholder_icon_; // Apply the icon effects on the uncompressed data. If the caller requests // an uncompressed icon, return the uncompressed result; otherwise, encode // the icon to a compressed icon, return the compressed result. if (icon_effects_) { - apps::ApplyIconEffects(icon_effects_, size_hint_in_dip_, &processed_image); - } - - if (icon_type_ == apps::mojom::IconType::kUncompressed || - icon_type_ == apps::mojom::IconType::kStandard) { - CompleteWithImageSkia(processed_image); + apps::ApplyIconEffects( + icon_effects_, size_hint_in_dip_, std::move(iv), + base::BindOnce(&IconLoadingPipeline::CompleteWithIconValue, + base::WrapRefCounted(this))); return; } - processed_image.MakeThreadSafe(); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&apps::EncodeImageToPngBytes, processed_image, - icon_scale_for_compressed_response_), - base::BindOnce(&IconLoadingPipeline::CompleteWithCompressed, - base::WrapRefCounted(this))); + CompleteWithIconValue(std::move(iv)); } void IconLoadingPipeline::CompleteWithCompressed(std::vector<uint8_t> data) { @@ -922,20 +1037,33 @@ std::move(callback_).Run(std::move(iv)); } -void IconLoadingPipeline::CompleteWithImageSkia(gfx::ImageSkia image) { +void IconLoadingPipeline::CompleteWithUncompressed( + apps::mojom::IconValuePtr iv) { DCHECK_NE(icon_type_, apps::mojom::IconType::kCompressed); DCHECK_NE(icon_type_, apps::mojom::IconType::kUnknown); - if (image.isNull()) { + if (iv->uncompressed.isNull()) { MaybeLoadFallbackOrCompleteEmpty(); return; } - apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); - iv->icon_type = icon_type_; - iv->uncompressed = std::move(image); - iv->is_placeholder_icon = is_placeholder_icon_; std::move(callback_).Run(std::move(iv)); } +void IconLoadingPipeline::CompleteWithIconValue(apps::mojom::IconValuePtr iv) { + if (icon_type_ == apps::mojom::IconType::kUncompressed || + icon_type_ == apps::mojom::IconType::kStandard) { + CompleteWithUncompressed(std::move(iv)); + return; + } + + iv->uncompressed.MakeThreadSafe(); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&apps::EncodeImageToPngBytes, iv->uncompressed, + icon_scale_for_compressed_response_), + base::BindOnce(&IconLoadingPipeline::CompleteWithCompressed, + base::WrapRefCounted(this))); +} + // Callback for reading uncompressed web app icons. void IconLoadingPipeline::OnReadWebAppIcon( std::map<int, SkBitmap> icon_bitmaps) { @@ -1248,8 +1376,10 @@ } image_skia.EnsureRepsForSupportedScales(); - ApplyIconEffects(icon_effects, size_hint_in_dip, &image_skia); - + if ((icon_effects & IconEffects::kCrOsStandardMask) && + (icon_effects & IconEffects::kCrOsStandardBackground)) { + image_skia = apps::ApplyBackgroundAndMask(image_skia); + } return image_skia; } @@ -1257,55 +1387,12 @@ void ApplyIconEffects(IconEffects icon_effects, int size_hint_in_dip, - gfx::ImageSkia* image_skia) { - extensions::ChromeAppIcon::ResizeFunction resize_function; -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (icon_effects & IconEffects::kResizeAndPad) { - // TODO(crbug.com/826982): MD post-processing is not always applied: "See - // legacy code: - // https://cs.chromium.org/search/?q=ChromeAppIconLoader&type=cs In one - // cases MD design is used in another not." - resize_function = - base::BindRepeating(&app_list::MaybeResizeAndPadIconForMd); - } - - if (icon_effects & IconEffects::kCrOsStandardMask) { - if (icon_effects & IconEffects::kCrOsStandardBackground) { - *image_skia = apps::ApplyBackgroundAndMask(*image_skia); - } else { - auto mask_image = LoadMaskImage(GetScaleToSize(*image_skia)); - *image_skia = - gfx::ImageSkiaOperations::CreateMaskedImage(*image_skia, mask_image); - } - } - - if (icon_effects & IconEffects::kCrOsStandardIcon) { - *image_skia = apps::CreateStandardIconImage(*image_skia); - } -#endif - - const bool from_bookmark = icon_effects & IconEffects::kRoundCorners; - - bool app_launchable = true; - // Only one badge can be visible at a time. - // Priority in which badges are applied (from the highest): Blocked > Paused > - // Chrome. This means than when apps are disabled or paused app type - // distinction information (Chrome vs Android) is lost. - extensions::ChromeAppIcon::Badge badge_type = - extensions::ChromeAppIcon::Badge::kNone; - if (icon_effects & IconEffects::kBlocked) { - badge_type = extensions::ChromeAppIcon::Badge::kBlocked; - app_launchable = false; - } else if (icon_effects & IconEffects::kPaused) { - badge_type = extensions::ChromeAppIcon::Badge::kPaused; - app_launchable = false; - } else if (icon_effects & IconEffects::kChromeBadge) { - badge_type = extensions::ChromeAppIcon::Badge::kChrome; - } - - extensions::ChromeAppIcon::ApplyEffects(size_hint_in_dip, resize_function, - app_launchable, from_bookmark, - badge_type, image_skia); + apps::mojom::IconValuePtr iv, + apps::mojom::Publisher::LoadIconCallback callback) { + scoped_refptr<IconLoadingPipeline> icon_loader = + base::MakeRefCounted<IconLoadingPipeline>(size_hint_in_dip, + std::move(callback)); + icon_loader->ApplyIconEffects(icon_effects, std::move(iv)); } void LoadIconFromExtension(apps::mojom::IconType icon_type,
diff --git a/chrome/browser/apps/app_service/app_icon_factory.h b/chrome/browser/apps/app_service/app_icon_factory.h index 45f7487..8e6c385 100644 --- a/chrome/browser/apps/app_service/app_icon_factory.h +++ b/chrome/browser/apps/app_service/app_icon_factory.h
@@ -119,11 +119,12 @@ int size_hint_in_dip); #endif // BUILDFLAG(IS_CHROMEOS_ASH) -// Modifies |image_skia| to apply icon post-processing effects like badging and +// Modifies |iv| to apply icon post-processing effects like badging and // desaturation to gray. void ApplyIconEffects(IconEffects icon_effects, int size_hint_in_dip, - gfx::ImageSkia* image_skia); + apps::mojom::IconValuePtr iv, + apps::mojom::Publisher::LoadIconCallback callback); // Loads an icon from an extension. void LoadIconFromExtension(apps::mojom::IconType icon_type,
diff --git a/chrome/browser/apps/app_service/app_icon_factory_unittest.cc b/chrome/browser/apps/app_service/app_icon_factory_unittest.cc index a1c4bc4..441aba2 100644 --- a/chrome/browser/apps/app_service/app_icon_factory_unittest.cc +++ b/chrome/browser/apps/app_service/app_icon_factory_unittest.cc
@@ -1111,9 +1111,13 @@ } gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia( - icon_bitmaps, /*icon_effects=*/apps::IconEffects::kCrOsStandardIcon, + icon_bitmaps, + /*icon_effects=*/apps::IconEffects::kCrOsStandardBackground | + apps::IconEffects::kCrOsStandardMask, /*size_hint_in_dip=*/32); + EnsureRepresentationsLoaded(converted_image); + const std::vector<ui::ScaleFactor>& scale_factors = ui::GetSupportedScaleFactors(); ASSERT_EQ(2U, scale_factors.size()); @@ -1122,14 +1126,14 @@ const float scale = ui::GetScaleForScaleFactor(scale_factors[i]); ASSERT_TRUE(converted_image.HasRepresentation(scale)); - // No colour in the upper left corner. + // No color in the upper left corner. EXPECT_FALSE( converted_image.GetRepresentation(scale).GetBitmap().getColor(0, 0)); + // Has color in the center. const SquareSizePx center_px = sizes_px[i] / 2; - EXPECT_EQ(colors[i], - converted_image.GetRepresentation(scale).GetBitmap().getColor( - center_px, center_px)); + EXPECT_TRUE(converted_image.GetRepresentation(scale).GetBitmap().getColor( + center_px, center_px)); } }
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc index 42d837f..bcb2d1e 100644 --- a/chrome/browser/apps/app_service/publishers/arc_apps.cc +++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -78,6 +78,21 @@ std::move(callback).Run(std::move(iv)); } +void UpdateIconImage(apps::mojom::Publisher::LoadIconCallback callback, + apps::mojom::IconValuePtr iv) { + if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) && + iv->icon_type == apps::mojom::IconType::kCompressed) { + iv->uncompressed.MakeThreadSafe(); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&apps::EncodeImageToPngBytes, iv->uncompressed, + /*rep_icon_scale=*/1.0f), + base::BindOnce(&CompleteWithCompressed, std::move(callback))); + return; + } + std::move(callback).Run(std::move(iv)); +} + void OnArcAppIconCompletelyLoaded( apps::mojom::IconType icon_type, int32_t size_hint_in_dip, @@ -126,8 +141,10 @@ iv->uncompressed = icon->image_skia(); } if (icon_effects != apps::IconEffects::kNone) { - apps::ApplyIconEffects(icon_effects, size_hint_in_dip, - &iv->uncompressed); + apps::ApplyIconEffects( + icon_effects, size_hint_in_dip, std::move(iv), + base::BindOnce(&UpdateIconImage, std::move(callback))); + return; } break; } @@ -136,17 +153,7 @@ break; } - if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) && - icon_type == apps::mojom::IconType::kCompressed) { - iv->uncompressed.MakeThreadSafe(); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&apps::EncodeImageToPngBytes, iv->uncompressed, - /*rep_icon_scale=*/1.0f), - base::BindOnce(&CompleteWithCompressed, std::move(callback))); - return; - } - std::move(callback).Run(std::move(iv)); + UpdateIconImage(std::move(callback), std::move(iv)); } void UpdateAppPermissions(
diff --git a/chrome/browser/apps/app_service/publishers/remote_apps.cc b/chrome/browser/apps/app_service/publishers/remote_apps.cc index 3a2060b5..ff8df41 100644 --- a/chrome/browser/apps/app_service/publishers/remote_apps.cc +++ b/chrome/browser/apps/app_service/publishers/remote_apps.cc
@@ -96,17 +96,19 @@ icon_image = delegate_->GetPlaceholderIcon(app_id, size_hint_in_dip); } - if (!icon_image.isNull()) { - icon->icon_type = icon_type; - icon->uncompressed = icon_image; - icon->is_placeholder_icon = is_placeholder_icon; - IconEffects icon_effects = (icon_type == mojom::IconType::kStandard) - ? IconEffects::kCrOsStandardIcon - : IconEffects::kResizeAndPad; - apps::ApplyIconEffects(icon_effects, size_hint_in_dip, &icon->uncompressed); + if (icon_image.isNull()) { + std::move(callback).Run(std::move(icon)); + return; } - std::move(callback).Run(std::move(icon)); + icon->icon_type = icon_type; + icon->uncompressed = icon_image; + icon->is_placeholder_icon = is_placeholder_icon; + IconEffects icon_effects = (icon_type == mojom::IconType::kStandard) + ? IconEffects::kCrOsStandardIcon + : IconEffects::kResizeAndPad; + apps::ApplyIconEffects(icon_effects, size_hint_in_dip, std::move(icon), + std::move(callback)); } void RemoteApps::Launch(const std::string& app_id,
diff --git a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc index 2f27bda8..fe0444e 100644 --- a/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc +++ b/chrome/browser/apps/app_shim/web_app_shim_manager_delegate_mac.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/web_applications/components/os_integration_manager.h" #include "chrome/browser/web_applications/components/web_app_shortcut_mac.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -172,9 +173,29 @@ return; } - apps::AppServiceProxyFactory::GetForProfile(profile) - ->BrowserAppLauncher() - ->LaunchAppWithParams(std::move(params)); + if (params.protocol_handler_launch_url.has_value()) { + GURL protocol_url = params.protocol_handler_launch_url.value(); + + auto launch_callback = base::BindOnce( + [](apps::AppLaunchParams params, Profile* profile, bool accepted) { + if (accepted) { + apps::AppServiceProxyFactory::GetForProfile(profile) + ->BrowserAppLauncher() + ->LaunchAppWithParams(std::move(params)); + } + }, + std::move(params), profile); + + // ShowWebAppProtocolHandlerIntentPicker keeps the `profile` alive through + // running of `launch_callback`. + chrome::ShowWebAppProtocolHandlerIntentPicker( + std::move(protocol_url), profile, app_id, std::move(launch_callback)); + + } else { + apps::AppServiceProxyFactory::GetForProfile(profile) + ->BrowserAppLauncher() + ->LaunchAppWithParams(std::move(params)); + } } void WebAppShimManagerDelegate::LaunchShim(
diff --git a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc index 9a5c2a28..9ae149c 100644 --- a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc +++ b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc
@@ -99,8 +99,8 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(AccessibilityManager::Get()->profile()); - auto event_args = std::make_unique<base::ListValue>(); - event_args->AppendString(ToString(command)); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(ToString(command))); auto event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_SWITCH_ACCESS_COMMAND, @@ -116,13 +116,12 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(AccessibilityManager::Get()->profile()); - auto event_args = std::make_unique<base::ListValue>(); - auto point_dict = std::make_unique<base::DictionaryValue>(); + base::Value point_dict(base::Value::Type::DICTIONARY); + point_dict.SetDoubleKey("x", point.x()); + point_dict.SetDoubleKey("y", point.y()); - point_dict->SetDouble("x", point.x()); - point_dict->SetDouble("y", point.y()); - - event_args->Append(std::move(point_dict)); + std::vector<base::Value> event_args; + event_args.push_back(std::move(point_dict)); auto event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_POINT_SCAN_SET, @@ -138,8 +137,8 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(AccessibilityManager::Get()->profile()); - auto event_args = std::make_unique<base::ListValue>(); - event_args->AppendString(ToString(command)); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(ToString(command))); auto event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_SWITCH_ACCESS_COMMAND,
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc index 360efc49..00e0eee 100644 --- a/chrome/browser/ash/accessibility/accessibility_manager.cc +++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -575,11 +575,10 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - auto event_args = std::make_unique<base::ListValue>(); auto event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_START, extensions::api::accessibility_private::OnTwoFingerTouchStart::kEventName, - std::move(event_args)); + std::vector<base::Value>()); event_router->BroadcastEvent(std::move(event)); } @@ -590,11 +589,10 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - auto event_args = std::make_unique<base::ListValue>(); auto event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_STOP, extensions::api::accessibility_private::OnTwoFingerTouchStop::kEventName, - std::move(event_args)); + std::vector<base::Value>()); event_router->BroadcastEvent(std::move(event)); } @@ -615,11 +613,10 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - std::unique_ptr<base::ListValue> event_args = - std::make_unique<base::ListValue>(); - event_args->AppendString(ui::ToString(gesture)); - event_args->AppendInteger(location.x()); - event_args->AppendInteger(location.y()); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(ui::ToString(gesture))); + event_args.push_back(base::Value(location.x())); + event_args.push_back(base::Value(location.y())); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE, extensions::api::accessibility_private::OnAccessibilityGesture:: @@ -912,14 +909,12 @@ extensions::EventRouter::Get(profile_); // Send an event to the Select-to-Speak extension requesting a state change. - std::unique_ptr<base::ListValue> event_args = - std::make_unique<base::ListValue>(); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events:: ACCESSIBILITY_PRIVATE_ON_SELECT_TO_SPEAK_STATE_CHANGE_REQUESTED, extensions::api::accessibility_private:: OnSelectToSpeakStateChangeRequested::kEventName, - std::move(event_args))); + std::vector<base::Value>())); event_router->DispatchEventWithLazyListener( extension_misc::kSelectToSpeakExtensionId, std::move(event)); } @@ -1464,12 +1459,10 @@ const std::string& extension_id = extension_misc::kChromeVoxExtensionId; - std::unique_ptr<base::ListValue> event_args = - std::make_unique<base::ListValue>(); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events::ACCESSIBILITY_PRIVATE_ON_INTRODUCE_CHROME_VOX, extensions::api::accessibility_private::OnIntroduceChromeVox::kEventName, - std::move(event_args))); + std::vector<base::Value>())); event_router->DispatchEventWithLazyListener(extension_id, std::move(event)); if (!chromevox_panel_) { @@ -1769,10 +1762,10 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile_); - auto event_args = std::make_unique<base::ListValue>(); - event_args->AppendString(AccessibilityPrivateEnumForAction(action)); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(AccessibilityPrivateEnumForAction(action))); if (value != 0.0) { - event_args->Append(value); + event_args.push_back(base::Value(value)); } auto event = std::make_unique<extensions::Event>(
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc index eaddc740..f83bfc0 100644 --- a/chrome/browser/ash/accessibility/dictation_browsertest.cc +++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -9,12 +9,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/timer/timer.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" -#include "chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h" #include "chrome/browser/speech/cros_speech_recognition_service_factory.h" #include "chrome/browser/speech/fake_speech_recognition_service.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/soda/soda_installer.h" +#include "components/soda/soda_installer_impl_chromeos.h" #include "content/public/test/browser_test.h" #include "content/public/test/fake_speech_recognition_manager.h" #include "media/mojo/mojom/speech_recognition_service.mojom.h"
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc index 6e96a0c..f899a7f 100644 --- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc +++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -33,6 +33,7 @@ #include "components/exo/surface.h" #include "components/exo/wm_helper.h" #include "components/language/core/browser/pref_names.h" +#include "components/live_caption/pref_names.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "ui/accessibility/accessibility_features.h"
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc index 1c46419..212802a 100644 --- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc +++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -34,6 +34,7 @@ #include "components/exo/shell_surface.h" #include "components/exo/shell_surface_util.h" #include "components/language/core/browser/pref_names.h" +#include "components/live_caption/pref_names.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "extensions/browser/event_router.h"
diff --git a/chrome/browser/ash/certificate_provider/certificate_provider_service_factory.cc b/chrome/browser/ash/certificate_provider/certificate_provider_service_factory.cc index 11946cc..5e6130d0 100644 --- a/chrome/browser/ash/certificate_provider/certificate_provider_service_factory.cc +++ b/chrome/browser/ash/certificate_provider/certificate_provider_service_factory.cc
@@ -86,8 +86,9 @@ int request_id) { api_cp::CertificatesUpdateRequest certificates_update_request; certificates_update_request.certificates_request_id = request_id; - auto event_args = std::make_unique<base::ListValue>(); - event_args->Append(certificates_update_request.ToValue()); + std::vector<base::Value> event_args; + event_args.push_back( + base::Value::FromUniquePtrValue(certificates_update_request.ToValue())); return std::make_unique<extensions::Event>( extensions::events::CERTIFICATEPROVIDER_ON_CERTIFICATES_UPDATE_REQUESTED, api_cp::OnCertificatesUpdateRequested::kEventName, std::move(event_args)); @@ -96,8 +97,8 @@ // Constructs the legacy "onCertificatesRequested" event. std::unique_ptr<extensions::Event> BuildOnCertificatesRequestedEvent( int request_id) { - auto event_args = std::make_unique<base::ListValue>(); - event_args->Append(request_id); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(request_id)); return std::make_unique<extensions::Event>( extensions::events::CERTIFICATEPROVIDER_ON_CERTIFICATES_REQUESTED, api_cp::OnCertificatesRequested::kEventName, std::move(event_args)); @@ -145,8 +146,8 @@ net::x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer()); request.certificate.assign(cert_der.begin(), cert_der.end()); - auto event_args = std::make_unique<base::ListValue>(); - event_args->Append(request.ToValue()); + std::vector<base::Value> event_args; + event_args.push_back(base::Value::FromUniquePtrValue(request.ToValue())); return std::make_unique<extensions::Event>( extensions::events::CERTIFICATEPROVIDER_ON_SIGNATURE_REQUESTED, @@ -196,9 +197,9 @@ } request.digest.resize(digest_len); - std::unique_ptr<base::ListValue> event_args(new base::ListValue); - event_args->AppendInteger(request_id); - event_args->Append(request.ToValue()); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(request_id)); + event_args.push_back(base::Value::FromUniquePtrValue(request.ToValue())); return std::make_unique<extensions::Event>( extensions::events::CERTIFICATEPROVIDER_ON_SIGN_DIGEST_REQUESTED,
diff --git a/chrome/browser/ash/crosapi/browser_loader.cc b/chrome/browser/ash/crosapi/browser_loader.cc index 4260257..9136d71 100644 --- a/chrome/browser/ash/crosapi/browser_loader.cc +++ b/chrome/browser/ash/crosapi/browser_loader.cc
@@ -15,6 +15,8 @@ #include "base/logging.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" +#include "base/values.h" +#include "base/version.h" #include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/ash/system_tray_client_impl.h" @@ -46,6 +48,22 @@ constexpr ComponentInfo kLacrosDogfoodStableInfo = { "lacros-dogfood-stable", "hnfmbeciphpghlfgpjfbcdifbknombnk"}; +// The rootfs lacros-chrome binary related files. +constexpr char kLacrosChromeBinary[] = "chrome"; +constexpr char kLacrosImage[] = "lacros.squash"; +constexpr char kLacrosMetadata[] = "metadata.json"; + +// The rootfs lacros-chrome binary related paths. +// Must be kept in sync with lacros upstart conf files. +constexpr char kRootfsLacrosMountPoint[] = "/run/lacros"; +constexpr char kRootfsLacrosPath[] = "/opt/google/lacros"; + +// Lacros upstart jobs for mounting/unmounting the lacros-chrome image. +// The conversion of upstart job names to dbus object paths is undocumented. See +// function nih_dbus_path in libnih for the implementation. +constexpr char kLacrosMounterUpstartJob[] = "lacros_2dmounter"; +constexpr char kLacrosUnmounterUpstartJob[] = "lacros_2dunmounter"; + ComponentInfo GetLacrosComponentInfo() { const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); if (cmdline->HasSwitch(browser_util::kLacrosStabilitySwitch)) { @@ -71,12 +89,18 @@ return GetLacrosComponentInfo().crx_id; } +// Returns whether lacros-chrome component is already installed. +bool CheckInstalledMayBlock( + scoped_refptr<component_updater::CrOSComponentManager> manager) { + return manager->IsRegisteredMayBlock(GetLacrosComponentName()); +} + // Returns whether lacros-fishfood component is already installed. // If it is, delete the user directory, too, because it will be // uninstalled. bool CheckInstalledAndMaybeRemoveUserDirectory( scoped_refptr<component_updater::CrOSComponentManager> manager) { - if (!manager->IsRegisteredMayBlock(GetLacrosComponentName())) + if (!CheckInstalledMayBlock(manager)) return false; // Since we're already on a background thread, delete the user-data-dir @@ -110,14 +134,20 @@ BrowserLoader::BrowserLoader( scoped_refptr<component_updater::CrOSComponentManager> manager) - : BrowserLoader(std::make_unique<DelegateImpl>(), manager) {} + : BrowserLoader(std::make_unique<DelegateImpl>(), + manager, + g_browser_process->component_updater(), + chromeos::UpstartClient::Get()) {} BrowserLoader::BrowserLoader( std::unique_ptr<Delegate> delegate, - scoped_refptr<component_updater::CrOSComponentManager> manager) + scoped_refptr<component_updater::CrOSComponentManager> manager, + component_updater::ComponentUpdateService* updater, + chromeos::UpstartClient* upstart_client) : delegate_(std::move(delegate)), component_manager_(manager), - component_update_service_(g_browser_process->component_updater()) { + component_update_service_(updater), + upstart_client_(upstart_client) { DCHECK(delegate_); DCHECK(component_manager_); } @@ -148,14 +178,134 @@ return; } + // TODO(b/188473251): Remove this check once rootfs lacros-chrome is in. + if (!base::PathExists( + base::FilePath(kRootfsLacrosPath).Append(kLacrosImage))) { + LOG(ERROR) << "Rootfs lacros image is missing. Going to load lacros " + "component instead."; + LoadStatefulLacros(std::move(callback)); + return; + } + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&CheckInstalledMayBlock, component_manager_), + base::BindOnce(&BrowserLoader::OnLoadSelection, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void BrowserLoader::OnLoadSelection(LoadCompletionCallback callback, + bool was_installed) { + // If there currently isn't a stateful lacros-chrome binary, proceed to use + // the rootfs lacros-chrome binary and start the installation of the + // stateful lacros-chrome binary in the background. + if (!was_installed) { + LoadRootfsLacros(std::move(callback)); + LoadStatefulLacros({}); + return; + } + + // Otherwise proceed to compare the lacros-chrome binary versions. + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&browser_util::GetRootfsLacrosVersionMayBlock, + base::FilePath(kRootfsLacrosPath).Append(kLacrosMetadata)), + base::BindOnce(&BrowserLoader::OnLoadVersionSelection, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void BrowserLoader::OnLoadVersionSelection( + LoadCompletionCallback callback, + base::Version rootfs_lacros_version) { + // Compare the rootfs vs stateful lacros-chrome binary versions. + // If the rootfs lacros-chrome is greater than or equal to the stateful + // lacros-chrome version, prioritize using the rootfs lacros-chrome and let + // stateful lacros-chrome update in the background. + if (rootfs_lacros_version.IsValid()) { + auto lacros_component_name = GetLacrosComponentName(); + for (const auto& component_info : + component_update_service_->GetComponents()) { + if (component_info.id != lacros_component_name) + continue; + if (component_info.version <= rootfs_lacros_version) { + LOG(WARNING) << "Stateful lacros version (" + << component_info.version.GetString() + << ") is older or same as the rootfs lacros version (" + << rootfs_lacros_version.GetString() + << ", proceeding to use rootfs lacros."; + LoadRootfsLacros(std::move(callback)); + LoadStatefulLacros({}); + return; + } + // Break out to use stateful lacros-chrome. + LOG(WARNING) + << "Stateful lacros version is newer than the one in rootfs, " + << "procceding to use stateful lacros."; + break; + } + } + LoadStatefulLacros(std::move(callback)); +} + +void BrowserLoader::LoadStatefulLacros(LoadCompletionCallback callback) { + LOG(WARNING) << "Loading stateful lacros."; + // Unmount the rootfs lacros-chrome if we want to use stateful lacros-chrome. + // This will keep stateful lacros-chrome only mounted and not hold the rootfs + // lacros-chrome mount until a `Unload`. + if (callback && base::PathExists(base::FilePath(kRootfsLacrosMountPoint) + .Append(kLacrosChromeBinary))) { + // Ignore the unmount result. + upstart_client_->StartJob(kLacrosUnmounterUpstartJob, {}, + base::BindOnce([](bool) {})); + } component_manager_->Load( GetLacrosComponentName(), component_updater::CrOSComponentManager::MountPolicy::kMount, // If a compatible installation exists, use that and download any updates // in the background. component_updater::CrOSComponentManager::UpdatePolicy::kDontForce, - base::BindOnce(&BrowserLoader::OnLoadComplete, weak_factory_.GetWeakPtr(), - std::move(callback))); + // If `callback` is null, means stateful lacros-chrome should be + // installed/updated but rootfs lacros-chrome will be used. + callback + ? base::BindOnce(&BrowserLoader::OnLoadComplete, + weak_factory_.GetWeakPtr(), std::move(callback)) + : base::BindOnce([](component_updater::CrOSComponentManager::Error, + const base::FilePath& path) {})); +} + +void BrowserLoader::LoadRootfsLacros(LoadCompletionCallback callback) { + LOG(WARNING) << "Loading rootfs lacros."; + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce( + &base::PathExists, + base::FilePath(kRootfsLacrosMountPoint).Append(kLacrosChromeBinary)), + base::BindOnce(&BrowserLoader::OnLoadRootfsLacros, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void BrowserLoader::OnLoadRootfsLacros(LoadCompletionCallback callback, + bool already_mounted) { + if (already_mounted) { + OnUpstartLacrosMounter(std::move(callback), true); + return; + } + upstart_client_->StartJob( + kLacrosMounterUpstartJob, {}, + base::BindOnce(&BrowserLoader::OnUpstartLacrosMounter, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void BrowserLoader::OnUpstartLacrosMounter(LoadCompletionCallback callback, + bool success) { + if (!success) + LOG(WARNING) << "Upstart failed to mount rootfs lacros."; + OnLoadComplete( + std::move(callback), component_updater::CrOSComponentManager::Error::NONE, + // If mounting wasn't successful, return a empty mount point to indicate + // failure. `OnLoadComplete` handles empty mount points and forwards the + // errors on the return callbacks. + success ? base::FilePath(kRootfsLacrosMountPoint) : base::FilePath()); } void BrowserLoader::Unload() { @@ -166,6 +316,10 @@ component_manager_), base::BindOnce(&BrowserLoader::OnCheckInstalled, weak_factory_.GetWeakPtr())); + // Unmount the rootfs lacros-chrome if it was mounted. + // Ignore the unmount result. + upstart_client_->StartJob(kLacrosUnmounterUpstartJob, {}, + base::BindOnce([](bool) {})); } void BrowserLoader::OnEvent(Events event, const std::string& id) { @@ -179,8 +333,9 @@ LoadCompletionCallback callback, component_updater::CrOSComponentManager::Error error, const base::FilePath& path) { - // Bail out on error. - if (error != component_updater::CrOSComponentManager::Error::NONE) { + // Bail out on error or empty `path`. + if (error != component_updater::CrOSComponentManager::Error::NONE || + path.empty()) { LOG(WARNING) << "Error loading lacros component image: " << static_cast<int>(error); std::move(callback).Run(base::FilePath());
diff --git a/chrome/browser/ash/crosapi/browser_loader.h b/chrome/browser/ash/crosapi/browser_loader.h index 92b5f6b8..71f3b01 100644 --- a/chrome/browser/ash/crosapi/browser_loader.h +++ b/chrome/browser/ash/crosapi/browser_loader.h
@@ -7,9 +7,11 @@ #include "base/callback.h" #include "base/files/file_path.h" +#include "base/gtest_prod_util.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/component_updater/cros_component_manager.h" +#include "chromeos/dbus/upstart/upstart_client.h" #include "components/component_updater/component_updater_service.h" namespace crosapi { @@ -32,14 +34,16 @@ scoped_refptr<component_updater::CrOSComponentManager> manager); // Constructor for testing. BrowserLoader(std::unique_ptr<Delegate> delegate, - scoped_refptr<component_updater::CrOSComponentManager> manager); + scoped_refptr<component_updater::CrOSComponentManager> manager, + component_updater::ComponentUpdateService* updater, + chromeos::UpstartClient* upstart_client); BrowserLoader(const BrowserLoader&) = delete; BrowserLoader& operator=(const BrowserLoader&) = delete; ~BrowserLoader() override; - // Starts to load lacros-chrome binary. + // Starts to load lacros-chrome binary or the rootfs lacros-chrome binary. // |callback| is called on completion with the path to the lacros-chrome on // success, or an empty filepath on failure. using LoadCompletionCallback = @@ -54,6 +58,31 @@ void OnEvent(Events event, const std::string& id) override; private: + FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, + OnLoadSelectionQuicklyChooseRootfs); + FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, OnLoadVersionSelectionStateful); + FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, OnLoadVersionSelectionRootfs); + FRIEND_TEST_ALL_PREFIXES(BrowserLoaderTest, + OnLoadVersionSelectionRootfsIsOlder); + + // Loads/Installs the stateful lacros component. + void LoadStatefulLacros(LoadCompletionCallback callback); + + // Loads the rootfs lacros component. + void LoadRootfsLacros(LoadCompletionCallback callback); + void OnLoadRootfsLacros(LoadCompletionCallback callback, + bool already_mounted); + + // Called to quickly load rootfs lacros if stateful lacros was missing and + // start the stateful lacros installation. + void OnLoadSelection(LoadCompletionCallback callback, bool was_installed); + + // Called to determine which lacros to load based on version (rootfs vs + // stateful). + void LoadVersionSelection(LoadCompletionCallback callback); + void OnLoadVersionSelection(LoadCompletionCallback callback, + base::Version rootfs_lacros_version); + // Called on the completion of loading. void OnLoadComplete(LoadCompletionCallback callback, component_updater::CrOSComponentManager::Error error, @@ -66,6 +95,9 @@ // Unloads the component. Called after system salt is available. void UnloadAfterCleanUp(const std::string& ignored_salt); + // Callback from upstart mounting lacros-chrome. + void OnUpstartLacrosMounter(LoadCompletionCallback callback, bool success); + // Allows stubbing out some methods for testing. std::unique_ptr<Delegate> delegate_; @@ -74,6 +106,10 @@ // May be null in tests. component_updater::ComponentUpdateService* const component_update_service_; + // Pointer held to `UpstartClient` for testing purposes. + // Otherwise, the lifetime is the same as `chromeos::UpstartClient::Get()`. + chromeos::UpstartClient* const upstart_client_; + base::WeakPtrFactory<BrowserLoader> weak_factory_{this}; };
diff --git a/chrome/browser/ash/crosapi/browser_loader_unittest.cc b/chrome/browser/ash/crosapi/browser_loader_unittest.cc index cbb1c23..1e11f758 100644 --- a/chrome/browser/ash/crosapi/browser_loader_unittest.cc +++ b/chrome/browser/ash/crosapi/browser_loader_unittest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ash/crosapi/browser_loader.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" @@ -11,10 +13,13 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/component_updater/fake_cros_component_manager.h" #include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h" +#include "chromeos/dbus/upstart/fake_upstart_client.h" +#include "components/component_updater/mock_component_updater_service.h" #include "components/update_client/update_client.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::Return; using update_client::UpdateClient; namespace crosapi { @@ -23,6 +28,9 @@ // Copied from browser_loader.cc constexpr char kLacrosComponentName[] = "lacros-dogfood-dev"; constexpr char kLacrosComponentId[] = "ldobopbhiamakmncndpkeelenhdmgfhk"; +constexpr char kLacrosMounterUpstartJob[] = "lacros_2dmounter"; + +} // namespace // Delegate for testing. class DelegateImpl : public BrowserLoader::Delegate { @@ -41,64 +49,137 @@ class BrowserLoaderTest : public testing::Test { public: - BrowserLoaderTest() { browser_util::SetLacrosEnabledForTest(true); } + BrowserLoaderTest() { + browser_util::SetLacrosEnabledForTest(true); + + // Create dependencies for object under test. + component_manager_ = + base::MakeRefCounted<component_updater::FakeCrOSComponentManager>(); + component_manager_->set_supported_components({kLacrosComponentName}); + component_manager_->ResetComponentState( + kLacrosComponentName, + component_updater::FakeCrOSComponentManager::ComponentInfo( + component_updater::CrOSComponentManager::Error::NONE, + base::FilePath("/install/path"), base::FilePath("/mount/path"))); + browser_part_ = std::make_unique<BrowserProcessPlatformPartTestApi>( + g_browser_process->platform_part()); + browser_part_->InitializeCrosComponentManager(component_manager_); + + // Create object under test. + auto delegate_ptr = std::make_unique<DelegateImpl>(); + delegate_ = delegate_ptr.get(); + + browser_loader_ = std::make_unique<BrowserLoader>( + std::move(delegate_ptr), component_manager_, + &mock_component_update_service_, &fake_upstart_client_); + } ~BrowserLoaderTest() override { + browser_part_->ShutdownCrosComponentManager(); browser_util::SetLacrosEnabledForTest(false); } // Public because this is test code. content::BrowserTaskEnvironment task_environment_; + + protected: + DelegateImpl* delegate_; + component_updater::MockComponentUpdateService mock_component_update_service_; + scoped_refptr<component_updater::FakeCrOSComponentManager> component_manager_; + chromeos::FakeUpstartClient fake_upstart_client_; + std::unique_ptr<BrowserProcessPlatformPartTestApi> browser_part_; + std::unique_ptr<BrowserLoader> browser_loader_; }; TEST_F(BrowserLoaderTest, ShowUpdateNotification) { - // Create dependencies for object under test. - scoped_refptr<component_updater::FakeCrOSComponentManager> component_manager = - base::MakeRefCounted<component_updater::FakeCrOSComponentManager>(); - component_manager->set_supported_components({kLacrosComponentName}); - component_manager->ResetComponentState( - kLacrosComponentName, - component_updater::FakeCrOSComponentManager::ComponentInfo( - component_updater::CrOSComponentManager::Error::NONE, - base::FilePath("/install/path"), base::FilePath("/mount/path"))); - BrowserProcessPlatformPartTestApi browser_part( - g_browser_process->platform_part()); - browser_part.InitializeCrosComponentManager(component_manager); - - // Create object under test. - auto delegate_ptr = std::make_unique<DelegateImpl>(); - DelegateImpl* delegate = delegate_ptr.get(); - BrowserLoader browser_loader(std::move(delegate_ptr), component_manager); - // Creating the loader does not trigger an update notification. - EXPECT_EQ(0, delegate->set_lacros_update_available_); + EXPECT_EQ(0, delegate_->set_lacros_update_available_); // The initial load of the component does not trigger an update notification. base::RunLoop run_loop; - browser_loader.Load(base::BindLambdaForTesting( + browser_loader_->Load(base::BindLambdaForTesting( [&](const base::FilePath&) { run_loop.Quit(); })); run_loop.Run(); - EXPECT_EQ(0, delegate->set_lacros_update_available_); + EXPECT_EQ(0, delegate_->set_lacros_update_available_); // Update check does not trigger an update notification. - browser_loader.OnEvent( + browser_loader_->OnEvent( UpdateClient::Observer::Events::COMPONENT_CHECKING_FOR_UPDATES, kLacrosComponentId); - EXPECT_EQ(0, delegate->set_lacros_update_available_); + EXPECT_EQ(0, delegate_->set_lacros_update_available_); // Update download does not trigger an update notification. - browser_loader.OnEvent( + browser_loader_->OnEvent( UpdateClient::Observer::Events::COMPONENT_UPDATE_DOWNLOADING, kLacrosComponentId); - EXPECT_EQ(0, delegate->set_lacros_update_available_); + EXPECT_EQ(0, delegate_->set_lacros_update_available_); // Update completion trigger the notification. - browser_loader.OnEvent(UpdateClient::Observer::Events::COMPONENT_UPDATED, - kLacrosComponentId); - EXPECT_EQ(1, delegate->set_lacros_update_available_); - - browser_part.ShutdownCrosComponentManager(); + browser_loader_->OnEvent(UpdateClient::Observer::Events::COMPONENT_UPDATED, + kLacrosComponentId); + EXPECT_EQ(1, delegate_->set_lacros_update_available_); } -} // namespace +TEST_F(BrowserLoaderTest, OnLoadSelectionQuicklyChooseRootfs) { + bool callback_called = false; + fake_upstart_client_.set_start_job_cb(base::BindRepeating( + [](bool* b, const std::string& job, + const std::vector<std::string>& upstart_env) { + EXPECT_EQ(job, kLacrosMounterUpstartJob); + *b = true; + return true; + }, + &callback_called)); + // Set `was_installed` to false, in order to quickly mount rootfs + // lacros-chrome. + browser_loader_->OnLoadSelection(base::BindOnce([](const base::FilePath&) {}), + false); + task_environment_.RunUntilIdle(); + EXPECT_TRUE(callback_called); +} + +TEST_F(BrowserLoaderTest, OnLoadVersionSelectionStateful) { + // Pass in an invalid `base::Version`. + browser_loader_->OnLoadVersionSelection({}, {}); +} + +TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfs) { + EXPECT_CALL(mock_component_update_service_, GetComponents()) + .WillOnce(Return(std::vector<component_updater::ComponentInfo>{ + {kLacrosComponentName, "", {}, base::Version("1.0.0")}})); + + bool callback_called = false; + fake_upstart_client_.set_start_job_cb(base::BindRepeating( + [](bool* b, const std::string& job, + const std::vector<std::string>& upstart_env) { + EXPECT_EQ(job, kLacrosMounterUpstartJob); + *b = true; + return true; + }, + &callback_called)); + // Pass in a rootfs lacros-chrome version that is newer. + browser_loader_->OnLoadVersionSelection( + base::BindOnce([](const base::FilePath&) {}), base::Version("2.0.0")); + task_environment_.RunUntilIdle(); + EXPECT_TRUE(callback_called); +} + +TEST_F(BrowserLoaderTest, OnLoadVersionSelectionRootfsIsOlder) { + EXPECT_CALL(mock_component_update_service_, GetComponents()) + .WillOnce(Return(std::vector<component_updater::ComponentInfo>{ + {kLacrosComponentName, "", {}, base::Version("3.0.0")}})); + + bool callback_called = false; + fake_upstart_client_.set_start_job_cb(base::BindRepeating( + [](bool* b, const std::string& job, + const std::vector<std::string>& upstart_env) { + *b = true; + return true; + }, + &callback_called)); + // Pass in a rootfs lacros-chrome version that is older. + browser_loader_->OnLoadVersionSelection({}, base::Version("2.0.0")); + EXPECT_FALSE(callback_called); +} + } // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc index c2593c0..4d9a985 100644 --- a/chrome/browser/ash/crosapi/browser_util.cc +++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -16,6 +16,7 @@ #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/json/json_reader.h" #include "base/path_service.h" #include "base/process/process_handle.h" #include "base/stl_util.h" @@ -66,6 +67,10 @@ absl::optional<bool> g_lacros_primary_browser_for_test; +// The rootfs lacros-chrome metadata keys. +constexpr char kLacrosMetadataContentKey[] = "content"; +constexpr char kLacrosMetadataVersionKey[] = "version"; + // Some account types require features that aren't yet supported by lacros. // See https://crbug.com/1080693 bool IsUserTypeAllowed(const User* user) { @@ -594,5 +599,41 @@ dict->SetString(user_id_hash, version.GetString()); } +base::Version GetRootfsLacrosVersionMayBlock( + const base::FilePath& version_file_path) { + if (!base::PathExists(version_file_path)) { + LOG(WARNING) << "The rootfs lacros-chrome metadata is missing."; + return {}; + } + + std::string metadata; + if (!base::ReadFileToString(version_file_path, &metadata)) { + PLOG(WARNING) << "Failed to read rootfs lacros-chrome metadata."; + return {}; + } + + absl::optional<base::Value> v = base::JSONReader::Read(metadata); + if (!v || !v->is_dict()) { + LOG(WARNING) << "Failed to parse rootfs lacros-chrome metadata."; + return {}; + } + + const base::Value* content = v->FindKey(kLacrosMetadataContentKey); + if (!content || !content->is_dict()) { + LOG(WARNING) + << "Failed to parse rootfs lacros-chrome metadata content key."; + return {}; + } + + const base::Value* version = content->FindKey(kLacrosMetadataVersionKey); + if (!version || !version->is_string()) { + LOG(WARNING) + << "Failed to parse rootfs lacros-chrome metadata version key."; + return {}; + } + + return base::Version{version->GetString()}; +} + } // namespace browser_util } // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_util.h b/chrome/browser/ash/crosapi/browser_util.h index f3ad60fb..0b8ded60 100644 --- a/chrome/browser/ash/crosapi/browser_util.h +++ b/chrome/browser/ash/crosapi/browser_util.h
@@ -189,6 +189,11 @@ const std::string& user_id_hash, const base::Version& version); +// Gets the version of the rootfs lacros-chrome. By reading the metadata json +// file in the correct format. +base::Version GetRootfsLacrosVersionMayBlock( + const base::FilePath& version_file_path); + } // namespace browser_util } // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc index 5378494..b7f37ee7 100644 --- a/chrome/browser/ash/crosapi/browser_util_unittest.cc +++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ash/crosapi/browser_util.h" #include "ash/constants/ash_features.h" +#include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/json/json_reader.h" #include "base/test/scoped_feature_list.h" @@ -493,4 +494,56 @@ EXPECT_TRUE(dict->Equals(&expected)); } +TEST_F(BrowserUtilTest, GetRootfsLacrosVersionMayBlock) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + const std::string kVersion = "91.0.4457"; + const std::string kContent = + "{\"content\":{\"version\":\"" + kVersion + "\"}}"; + auto path = tmp_dir.GetPath().Append("file"); + ASSERT_TRUE(base::WriteFile(path, kContent)); + + EXPECT_EQ(browser_util::GetRootfsLacrosVersionMayBlock(path), + base::Version(kVersion)); +} + +TEST_F(BrowserUtilTest, GetRootfsLacrosVersionMayBlockMissingVersion) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + const std::string kContent = "{\"content\":{}}"; + auto path = tmp_dir.GetPath().Append("file"); + ASSERT_TRUE(base::WriteFile(path, kContent)); + + EXPECT_FALSE(browser_util::GetRootfsLacrosVersionMayBlock(path).IsValid()); +} + +TEST_F(BrowserUtilTest, GetRootfsLacrosVersionMayBlockMissingContent) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + const std::string kContent = "{}"; + auto path = tmp_dir.GetPath().Append("file"); + ASSERT_TRUE(base::WriteFile(path, kContent)); + + EXPECT_FALSE(browser_util::GetRootfsLacrosVersionMayBlock(path).IsValid()); +} + +TEST_F(BrowserUtilTest, GetRootfsLacrosVersionMayBlockMissingFile) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + auto bad_path = tmp_dir.GetPath().Append("file"); + + EXPECT_FALSE( + browser_util::GetRootfsLacrosVersionMayBlock(bad_path).IsValid()); +} + +TEST_F(BrowserUtilTest, GetRootfsLacrosVersionMayBlockBadJson) { + base::ScopedTempDir tmp_dir; + ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); + const std::string kContent = "!@#$"; + auto path = tmp_dir.GetPath().Append("file"); + ASSERT_TRUE(base::WriteFile(path, kContent)); + + EXPECT_FALSE(browser_util::GetRootfsLacrosVersionMayBlock(path).IsValid()); +} + } // namespace crosapi
diff --git a/chrome/browser/ash/file_system_provider/extension_provider.cc b/chrome/browser/ash/file_system_provider/extension_provider.cc index 5e69307..b084724 100644 --- a/chrome/browser/ash/file_system_provider/extension_provider.cc +++ b/chrome/browser/ash/file_system_provider/extension_provider.cc
@@ -110,7 +110,7 @@ std::make_unique<extensions::Event>( extensions::events::FILE_SYSTEM_PROVIDER_ON_MOUNT_REQUESTED, extensions::api::file_system_provider::OnMountRequested::kEventName, - std::make_unique<base::ListValue>())); + std::vector<base::Value>())); return true; }
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc index 2ff2e2a..ac831919 100644 --- a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc +++ b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc
@@ -35,6 +35,7 @@ #include "chromeos/login/auth/user_context.h" #include "components/account_id/account_id.h" #include "components/policy/proto/chrome_device_policy.pb.h" +#include "components/services/app_service/public/mojom/types.mojom.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "components/user_manager/user_type.h" @@ -301,8 +302,24 @@ base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) ? apps::IconEffects::kCrOsStandardIcon : apps::IconEffects::kResizeAndPad; - apps::ApplyIconEffects(icon_effects, 64, &icon); - CheckIconsEqual(icon, item->GetDefaultIcon()); + + base::RunLoop run_loop; + apps::mojom::IconValuePtr output_data = apps::mojom::IconValue::New(); + apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); + iv->icon_type = apps::mojom::IconType::kStandard; + iv->uncompressed = icon; + iv->is_placeholder_icon = true; + apps::ApplyIconEffects(icon_effects, 64, std::move(iv), + base::BindOnce( + [](apps::mojom::IconValuePtr* result, + base::OnceClosure load_app_icon_callback, + apps::mojom::IconValuePtr icon) { + *result = std::move(icon); + std::move(load_app_icon_callback).Run(); + }, + &output_data, run_loop.QuitClosure())); + run_loop.Run(); + CheckIconsEqual(output_data->uncompressed, item->GetDefaultIcon()); } IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, AddAppError) {
diff --git a/chrome/browser/autofill/credit_card_accessory_controller_impl.cc b/chrome/browser/autofill/credit_card_accessory_controller_impl.cc index ed03b04..7467e8a9 100644 --- a/chrome/browser/autofill/credit_card_accessory_controller_impl.cc +++ b/chrome/browser/autofill/credit_card_accessory_controller_impl.cc
@@ -21,6 +21,7 @@ #include "components/autofill/core/browser/autofill_browser_util.h" #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -41,6 +42,27 @@ /*is_password=*/false, enabled)); } +void AddCardDetailsToUserInfo(const CreditCard& card, + UserInfo* user_info, + std::u16string cvc, + bool enabled) { + if (card.HasValidExpirationDate()) { + AddSimpleField(card.Expiration2DigitMonthAsString(), user_info, enabled); + AddSimpleField(card.Expiration4DigitYearAsString(), user_info, enabled); + } else { + AddSimpleField(std::u16string(), user_info, enabled); + AddSimpleField(std::u16string(), user_info, enabled); + } + + if (card.HasNameOnCard()) { + AddSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL), user_info, + enabled); + } else { + AddSimpleField(std::u16string(), user_info, enabled); + } + AddSimpleField(cvc, user_info, enabled); +} + UserInfo TranslateCard(const CreditCard* data, bool enabled) { DCHECK(data); @@ -50,21 +72,20 @@ user_info.add_field(UserInfo::Field(obfuscated_number, obfuscated_number, data->guid(), /*is_password=*/false, enabled)); + AddCardDetailsToUserInfo(*data, &user_info, std::u16string(), enabled); - if (data->HasValidExpirationDate()) { - AddSimpleField(data->Expiration2DigitMonthAsString(), &user_info, enabled); - AddSimpleField(data->Expiration4DigitYearAsString(), &user_info, enabled); - } else { - AddSimpleField(std::u16string(), &user_info, enabled); - AddSimpleField(std::u16string(), &user_info, enabled); - } + return user_info; +} - if (data->HasNameOnCard()) { - AddSimpleField(data->GetRawInfo(autofill::CREDIT_CARD_NAME_FULL), - &user_info, enabled); - } else { - AddSimpleField(std::u16string(), &user_info, enabled); - } +UserInfo TranslateCachedCard(const CachedServerCardInfo* data, bool enabled) { + DCHECK(data); + + const CreditCard& card = data->card; + UserInfo user_info(card.network()); + + AddSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NUMBER), &user_info, + enabled); + AddCardDetailsToUserInfo(card, &user_info, data->cvc, enabled); return user_info; } @@ -88,11 +109,26 @@ bool allow_filling = valid_manager && ShouldAllowCreditCardFallbacks( GetManager()->client(), GetManager()->last_query_form()); - std::transform(cards_cache_.begin(), cards_cache_.end(), - std::back_inserter(info_to_add), - [allow_filling](const CreditCard* data) { - return TranslateCard(data, allow_filling); - }); + + if (!cached_server_cards_.empty()) { + // Add the cached server cards first, so that they show up on the top of the + // manual filling view. + std::transform(cached_server_cards_.begin(), cached_server_cards_.end(), + std::back_inserter(info_to_add), + [allow_filling](const CachedServerCardInfo* data) { + return TranslateCachedCard(data, allow_filling); + }); + } + // Only add cards that are not present in the cache. Otherwise, we might + // show duplicates. + for (auto* card : cards_cache_) { + if (cached_server_cards_.empty() || + !GetManager() + ->credit_card_access_manager() + ->IsCardPresentInUnmaskedCache(card->server_id())) { + info_to_add.push_back(TranslateCard(card, allow_filling)); + } + } const std::vector<FooterCommand> footer_commands = {FooterCommand( l10n_util::GetStringUTF16( @@ -200,6 +236,7 @@ FetchSuggestionsFromPersonalDataManager(); } else { cards_cache_.clear(); // If cards cannot be filled, don't show them. + cached_server_cards_.clear(); } absl::optional<AccessorySheetData> data = GetSheetData(); if (source_observer_) { @@ -288,6 +325,18 @@ cards_cache_ = personal_data_manager_->GetCreditCardsToSuggest( /*include_server_cards=*/true); } + // TODO(crbug.com/1196021) Update the below logic to allow for showing only + // virtual cards if the kAutofillShowUnmaskedCachedCardInManualFillingView is + // disabled. + if (GetManager() && GetManager()->credit_card_access_manager() && + base::FeatureList::IsEnabled( + autofill::features:: + kAutofillShowUnmaskedCachedCardInManualFillingView)) { + cached_server_cards_ = + GetManager()->credit_card_access_manager()->GetCachedUnmaskedCards(); + } else { + cached_server_cards_.clear(); // No data available. + } } base::WeakPtr<ManualFillingController>
diff --git a/chrome/browser/autofill/credit_card_accessory_controller_impl.h b/chrome/browser/autofill/credit_card_accessory_controller_impl.h index 347b9cf8..359ee70 100644 --- a/chrome/browser/autofill/credit_card_accessory_controller_impl.h +++ b/chrome/browser/autofill/credit_card_accessory_controller_impl.h
@@ -77,6 +77,11 @@ autofill::BrowserAutofillManager* af_manager_for_testing_ = nullptr; autofill::AutofillDriver* af_driver_for_testing_ = nullptr; + // Cached cards that are already unmasked by the user. These are shown to the + // user in plaintext and won't require any authentication when filling is + // triggered. + std::vector<const CachedServerCardInfo*> cached_server_cards_; + // The observer to notify if available suggestions change. FillingSourceObserver source_observer_;
diff --git a/chrome/browser/autofill/credit_card_accessory_controller_impl_unittest.cc b/chrome/browser/autofill/credit_card_accessory_controller_impl_unittest.cc index e29b6408..7320c92 100644 --- a/chrome/browser/autofill/credit_card_accessory_controller_impl_unittest.cc +++ b/chrome/browser/autofill/credit_card_accessory_controller_impl_unittest.cc
@@ -17,6 +17,7 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_personal_data_manager.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/unique_ids.h" #include "components/strings/grit/components_strings.h" @@ -121,6 +122,8 @@ &data_manager_)) {} void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + autofill::features::kAutofillShowUnmaskedCachedCardInManualFillingView); ChromeRenderViewHostTestHarness::SetUp(); NavigateAndCommit(GURL(kExampleSite)); SetFormOrigin(GURL(kExampleSite)); @@ -160,6 +163,25 @@ TestBrowserAutofillManager af_manager_; base::MockCallback<AccessoryController::FillingSourceObserver> filling_source_observer_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +class CreditCardAccessoryControllerTestWithoutSupportingUnmaskedCards + : public CreditCardAccessoryControllerTest { + public: + void SetUp() override { + scoped_feature_list_.InitAndDisableFeature( + autofill::features::kAutofillShowUnmaskedCachedCardInManualFillingView); + ChromeRenderViewHostTestHarness::SetUp(); + NavigateAndCommit(GURL(kExampleSite)); + SetFormOrigin(GURL(kExampleSite)); + FocusWebContentsOnMainFrame(); + + CreditCardAccessoryControllerImpl::CreateForWebContentsForTesting( + web_contents(), mock_mf_controller_.AsWeakPtr(), &data_manager_, + &af_manager_, &mock_af_driver_); + data_manager_.SetPrefService(profile()->GetPrefs()); + } }; TEST_F(CreditCardAccessoryControllerTest, RefreshSuggestions) { @@ -185,6 +207,7 @@ .AppendSimpleField(card.Expiration2DigitMonthAsString()) .AppendSimpleField(card.Expiration4DigitYearAsString()) .AppendSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)) + .AppendSimpleField(std::u16string()) .Build()); } @@ -222,6 +245,9 @@ card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL), /*is_obfuscated=*/false, /*selectable=*/false) + .AppendField(std::u16string(), std::u16string(), + /*is_obfuscated=*/false, + /*selectable=*/false) .Build()); } @@ -260,4 +286,121 @@ controller()->OnFillingTriggered(field_id, field); } +TEST_F(CreditCardAccessoryControllerTest, + RefreshSuggestionsUnmaskedCachedCard) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + autofill::features::kAutofillShowUnmaskedCachedCardInManualFillingView); + // Store a full server card in the credit_card_access_manager's + // unmasked_cards_cache. + autofill::CreditCard card = test::GetCreditCard(); + card.set_record_type(CreditCard::FULL_SERVER_CARD); + data_manager_.AddCreditCard(card); + std::u16string cvc = u"123"; + af_manager_.credit_card_access_manager()->CacheUnmaskedCardInfo(card, cvc); + autofill::AccessorySheetData result(autofill::AccessoryTabType::CREDIT_CARDS, + std::u16string()); + + EXPECT_CALL(mock_mf_controller_, RefreshSuggestions(_)) + .WillOnce(SaveArg<0>(&result)); + ASSERT_TRUE(controller()); + controller()->RefreshSuggestions(); + + EXPECT_EQ(result, controller()->GetSheetData()); + // Verify that the full card number and the cvc fields are added to the + // accessory sheet data. + EXPECT_EQ( + result, + CreditCardAccessorySheetDataBuilder() + .AddUserInfo(kVisaCard) + .AppendSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NUMBER)) + .AppendSimpleField(card.Expiration2DigitMonthAsString()) + .AppendSimpleField(card.Expiration4DigitYearAsString()) + .AppendSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)) + .AppendSimpleField(cvc) + .Build()); +} + +TEST_F(CreditCardAccessoryControllerTest, UnmaskedCacheCardsReorderedToTheTop) { + // Add a masked card to PersonalDataManager. + autofill::CreditCard masked_card = test::GetMaskedServerCard(); + data_manager_.AddCreditCard(masked_card); + // Add a full server card to PersonalDataManager and also cache it in hte + // CreditCardAccessManager. + autofill::CreditCard unmasked_card = test::GetCreditCard(); + unmasked_card.set_record_type(CreditCard::FULL_SERVER_CARD); + data_manager_.AddCreditCard(unmasked_card); + std::u16string cvc = u"123"; + af_manager_.credit_card_access_manager()->CacheUnmaskedCardInfo(unmasked_card, + cvc); + autofill::AccessorySheetData result(autofill::AccessoryTabType::CREDIT_CARDS, + std::u16string()); + + EXPECT_CALL(mock_mf_controller_, RefreshSuggestions(_)) + .WillOnce(SaveArg<0>(&result)); + ASSERT_TRUE(controller()); + controller()->RefreshSuggestions(); + + EXPECT_EQ(result, controller()->GetSheetData()); + // Verify that the unmasked card is at the top followed by the masked card. + EXPECT_EQ( + result, + CreditCardAccessorySheetDataBuilder() + .AddUserInfo(kVisaCard) + .AppendSimpleField( + unmasked_card.GetRawInfo(autofill::CREDIT_CARD_NUMBER)) + .AppendSimpleField(unmasked_card.Expiration2DigitMonthAsString()) + .AppendSimpleField(unmasked_card.Expiration4DigitYearAsString()) + .AppendSimpleField( + unmasked_card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)) + .AppendSimpleField(cvc) + .AddUserInfo(kMasterCard) + .AppendField(masked_card.ObfuscatedLastFourDigits(), + masked_card.ObfuscatedLastFourDigits(), + masked_card.guid(), + /*is_obfuscated=*/false, + /*selectable=*/true) + .AppendSimpleField(masked_card.Expiration2DigitMonthAsString()) + .AppendSimpleField(masked_card.Expiration4DigitYearAsString()) + .AppendSimpleField( + masked_card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)) + .AppendSimpleField(std::u16string()) + .Build()); +} + +TEST_F(CreditCardAccessoryControllerTestWithoutSupportingUnmaskedCards, + RefreshSuggestionsUnmaskedCachedCard) { + // Store a full server card in the credit_card_access_manager's + // unmasked_cards_cache. + autofill::CreditCard card = test::GetCreditCard(); + card.set_record_type(CreditCard::FULL_SERVER_CARD); + data_manager_.AddCreditCard(card); + std::u16string cvc = u"123"; + af_manager_.credit_card_access_manager()->CacheUnmaskedCardInfo(card, cvc); + autofill::AccessorySheetData result(autofill::AccessoryTabType::CREDIT_CARDS, + std::u16string()); + + EXPECT_CALL(mock_mf_controller_, RefreshSuggestions(_)) + .WillOnce(SaveArg<0>(&result)); + ASSERT_TRUE(controller()); + controller()->RefreshSuggestions(); + + EXPECT_EQ(result, controller()->GetSheetData()); + // Since the experiment is disabled, verify that the only the obfuscated last + // four and no cvc is added to the accessory sheet data. + EXPECT_EQ( + result, + CreditCardAccessorySheetDataBuilder() + .AddUserInfo(kVisaCard) + .AppendField(card.ObfuscatedLastFourDigits(), + card.ObfuscatedLastFourDigits(), card.guid(), + /*is_obfuscated=*/false, + /*selectable=*/true) + .AppendSimpleField(card.Expiration2DigitMonthAsString()) + .AppendSimpleField(card.Expiration4DigitYearAsString()) + .AppendSimpleField(card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL)) + .AppendSimpleField(std::u16string()) + .Build()); +} + } // namespace autofill
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 9d05f5f..4f322dce5 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1443,7 +1443,8 @@ TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemovePersistentIsolatedOrigins) { PrefService* prefs = GetProfile()->GetPrefs(); - // Add foo.com to the list of stored isolated origins. + // Add foo.com to the list of stored user-triggered isolated origins and + // bar.com to the list of stored web-triggered isolated origins. base::ListValue list; list.AppendString("http://foo.com"); prefs->Set(site_isolation::prefs::kUserTriggeredIsolatedOrigins, list); @@ -1451,6 +1452,12 @@ prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + base::DictionaryValue dict; + dict.SetKey("https://bar.com", util::TimeToValue(base::Time::Now())); + prefs->Set(site_isolation::prefs::kWebTriggeredIsolatedOrigins, dict); + EXPECT_FALSE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); // Clear history and ensure the stored isolated origins are cleared. BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(), @@ -1459,13 +1466,20 @@ prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + EXPECT_TRUE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); - // Re-add foo.com to stored isolated origins. + // Re-add foo.com and bar.com to stored isolated origins. prefs->Set(site_isolation::prefs::kUserTriggeredIsolatedOrigins, list); EXPECT_FALSE( prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + prefs->Set(site_isolation::prefs::kWebTriggeredIsolatedOrigins, dict); + EXPECT_FALSE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); // Now clear cookies and other site data, and ensure foo.com is cleared. // Note that this uses a short time period to document that time ranges are @@ -1476,13 +1490,20 @@ prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + EXPECT_TRUE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); - // Re-add foo.com. + // Re-add foo.com and bar.com. prefs->Set(site_isolation::prefs::kUserTriggeredIsolatedOrigins, list); EXPECT_FALSE( prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + prefs->Set(site_isolation::prefs::kWebTriggeredIsolatedOrigins, dict); + EXPECT_FALSE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); // Clear the isolated origins data type. BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(), @@ -1491,13 +1512,20 @@ prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + EXPECT_TRUE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); - // Re-add foo.com. + // Re-add foo.com and bar.com. prefs->Set(site_isolation::prefs::kUserTriggeredIsolatedOrigins, list); EXPECT_FALSE( prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + prefs->Set(site_isolation::prefs::kWebTriggeredIsolatedOrigins, dict); + EXPECT_FALSE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); // Clear both history and site data, and ensure the stored isolated origins // are cleared. @@ -1508,6 +1536,9 @@ prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins) ->GetList() .empty()); + EXPECT_TRUE( + prefs->GetDictionary(site_isolation::prefs::kWebTriggeredIsolatedOrigins) + ->empty()); } // Test that clearing history deletes favicons not associated with bookmarks.
diff --git a/chrome/browser/cart/cart_discount_link_fetcher.cc b/chrome/browser/cart/cart_discount_link_fetcher.cc index 18dbfbd7..bc3a451 100644 --- a/chrome/browser/cart/cart_discount_link_fetcher.cc +++ b/chrome/browser/cart/cart_discount_link_fetcher.cc
@@ -25,19 +25,19 @@ const int64_t kTimeoutMs = 30000; } // namespace +CartDiscountLinkFetcher::~CartDiscountLinkFetcher() = default; + void CartDiscountLinkFetcher::Fetch( std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory, cart_db::ChromeCartContentProto cart_content_proto, CartDiscountLinkFetcherCallback callback) { - std::string default_url = cart_content_proto.merchant_cart_url(); auto fetcher = CreateEndpointFetcher(std::move(pending_factory), std::move(cart_content_proto)); auto* const fetcher_ptr = fetcher.get(); fetcher_ptr->PerformRequest( - base::BindOnce(&OnLinkFetched, std::move(fetcher), std::move(callback), - std::move(default_url)), + base::BindOnce(&OnLinkFetched, std::move(fetcher), std::move(callback)), nullptr); } @@ -146,25 +146,21 @@ void CartDiscountLinkFetcher::OnLinkFetched( std::unique_ptr<EndpointFetcher> endpoint_fetcher, CartDiscountLinkFetcherCallback callback, - std::string default_url, std::unique_ptr<EndpointResponse> responses) { VLOG(2) << "Response: " << responses->response; DCHECK(responses) << "responses should not be null"; if (!responses) { - std::move(callback).Run(std::move(default_url)); + std::move(callback).Run(GURL()); return; } absl::optional<base::Value> value = base::JSONReader::Read(responses->response); - if (!value || !value->is_dict()) { + if (!value || !value->is_dict() || !value->FindKey("url")) { NOTREACHED() << "empty response or wrong format"; - std::move(callback).Run(std::move(default_url)); + std::move(callback).Run(GURL()); return; } - - std::string url = value->FindKey("url")->GetString(); - - std::move(callback).Run(std::move(url)); + std::move(callback).Run(GURL(value->FindKey("url")->GetString())); }
diff --git a/chrome/browser/cart/cart_discount_link_fetcher.h b/chrome/browser/cart/cart_discount_link_fetcher.h index 7dc20d1..6cd45c71 100644 --- a/chrome/browser/cart/cart_discount_link_fetcher.h +++ b/chrome/browser/cart/cart_discount_link_fetcher.h
@@ -15,10 +15,12 @@ // This is used to get an encrypted discount link. class CartDiscountLinkFetcher { public: - using CartDiscountLinkFetcherCallback = base::OnceCallback<void(std::string)>; + using CartDiscountLinkFetcherCallback = base::OnceCallback<void(const GURL&)>; + + virtual ~CartDiscountLinkFetcher(); // Fetches the encrypted link for the given |cart_content_proto|. - static void Fetch( + virtual void Fetch( std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory, cart_db::ChromeCartContentProto cart_content_proto, CartDiscountLinkFetcherCallback callback); @@ -34,7 +36,6 @@ cart_db::ChromeCartContentProto cart_content_proto); static void OnLinkFetched(std::unique_ptr<EndpointFetcher> endpoint_fetcher, CartDiscountLinkFetcherCallback callback, - std::string default_url, std::unique_ptr<EndpointResponse> responses); };
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc index e5610ee9..c16dea46 100644 --- a/chrome/browser/cart/cart_service.cc +++ b/chrome/browser/cart/cart_service.cc
@@ -16,11 +16,13 @@ #include "chrome/grit/browser_resources.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "components/search/ntp_features.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/re2/src/re2/re2.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -92,7 +94,8 @@ ServiceAccessType::EXPLICIT_ACCESS)), domain_name_mapping_(JSONToDictionary(IDR_CART_DOMAIN_NAME_MAPPING_JSON)), domain_cart_url_mapping_( - JSONToDictionary(IDR_CART_DOMAIN_CART_URL_MAPPING_JSON)) { + JSONToDictionary(IDR_CART_DOMAIN_CART_URL_MAPPING_JSON)), + discount_link_fetcher_(std::make_unique<CartDiscountLinkFetcher>()) { if (history_service_) { history_service_observation_.Observe(history_service_); } @@ -117,6 +120,7 @@ registry->RegisterIntegerPref(prefs::kCartModuleWelcomeSurfaceShownTimes, 0); registry->RegisterBooleanPref(prefs::kCartDiscountAcknowledged, false); registry->RegisterBooleanPref(prefs::kCartDiscountEnabled, false); + registry->RegisterDictionaryPref(prefs::kCartUsedDiscounts); } void CartService::Hide() { @@ -293,8 +297,53 @@ void CartService::GetDiscountURL( const GURL& cart_url, base::OnceCallback<void(const ::GURL&)> callback) { - // TODO(crbug.com/1204146): Add logic here to fetch discount URL from service. - std::move(callback).Run(cart_url); + if (!IsPartnerMerchant(cart_url) || !IsCartDiscountEnabled()) { + std::move(callback).Run(cart_url); + return; + } + LoadCart(eTLDPlusOne(cart_url), + base::BindOnce(&CartService::OnGetDiscountURL, + weak_ptr_factory_.GetWeakPtr(), cart_url, + std::move(callback))); +} + +void CartService::OnGetDiscountURL( + const GURL& default_cart_url, + base::OnceCallback<void(const ::GURL&)> callback, + bool success, + std::vector<CartDB::KeyAndValue> proto_pairs) { + DCHECK_EQ(proto_pairs.size(), 1U); + if (proto_pairs.size() != 1U) { + std::move(callback).Run(default_cart_url); + return; + } + auto& cart_proto = proto_pairs[0].second; + if (cart_proto.discount_info().discount_info().empty()) { + std::move(callback).Run(default_cart_url); + return; + } + auto pending_factory = profile_->GetDefaultStoragePartition() + ->GetURLLoaderFactoryForBrowserProcess() + ->Clone(); + + discount_link_fetcher_->Fetch( + std::move(pending_factory), cart_proto, + base::BindOnce(&CartService::OnDiscountURLFetched, + weak_ptr_factory_.GetWeakPtr(), default_cart_url, + std::move(callback), cart_proto)); +} + +void CartService::OnDiscountURLFetched( + const GURL& default_cart_url, + base::OnceCallback<void(const ::GURL&)> callback, + const cart_db::ChromeCartContentProto& cart_proto, + const GURL& discount_url) { + std::move(callback).Run(discount_url.is_valid() ? discount_url + : default_cart_url); + if (discount_url.is_valid()) { + CacheUsedDiscounts(cart_proto); + CleanUpDiscounts(cart_proto); + } } void CartService::LoadCartsWithFakeData(CartDB::LoadCallback callback) { @@ -580,53 +629,34 @@ weak_ptr_factory_.GetWeakPtr())); } -void CartService::UpdateDiscounts( - const std::string& domain, - const double timestamp, - const std::vector<cart_db::DiscountInfoProto> discount_infos) { - auto update_discounts_callback = base::BindOnce( - &CartService::OnUpdateDiscount, weak_ptr_factory_.GetWeakPtr(), domain, - std::move(discount_infos), timestamp); - - cart_db_->LoadCart(domain, std::move(update_discounts_callback)); -} - -void CartService::OnUpdateDiscount( - const std::string& domain, - const std::vector<cart_db::DiscountInfoProto> discount_infos, - const double timestamp, - bool success, - std::vector<CartDB::KeyAndValue> proto_pairs) { - if (!success || proto_pairs.size() == 0) { +void CartService::UpdateDiscounts(const GURL& cart_url, + cart_db::ChromeCartContentProto new_proto) { + if (!cart_url.is_valid()) { + VLOG(1) << __func__ + << "update discounts with invalid cart_url: " << cart_url; return; } - DCHECK_EQ(1U, proto_pairs.size()); - - auto cart_proto = proto_pairs[0].second; - - cart_proto.mutable_discount_info()->set_last_fetched_timestamp(timestamp); - - if (discount_infos.empty()) { - cart_proto.mutable_discount_info()->clear_discount_info(); - } else { - for (cart_db::DiscountInfoProto discount_info : discount_infos) { - cart_db::DiscountInfoProto* added_discount = - cart_proto.mutable_discount_info()->add_discount_info(); - - added_discount->set_rule_id(discount_info.rule_id()); - if (discount_info.has_amount_off()) { - added_discount->set_allocated_amount_off( - discount_info.release_amount_off()); - } else { - added_discount->set_percent_off(discount_info.percent_off()); + if (new_proto.has_discount_info() && + !new_proto.discount_info().discount_info().empty()) { + // Filter used discounts. + std::vector<cart_db::DiscountInfoProto> discount_info_protos; + for (const cart_db::DiscountInfoProto& proto : + new_proto.discount_info().discount_info()) { + if (!IsDiscountUsed(proto.rule_id())) { + discount_info_protos.emplace_back(proto); } - added_discount->set_raw_merchant_offer_id( - discount_info.raw_merchant_offer_id()); + } + if (discount_info_protos.empty()) { + new_proto.clear_discount_info(); + } else { + *new_proto.mutable_discount_info()->mutable_discount_info() = { + discount_info_protos.begin(), discount_info_protos.end()}; } } - cart_db_->AddCart(domain, std::move(cart_proto), + std::string domain = eTLDPlusOne(cart_url); + cart_db_->AddCart(domain, std::move(new_proto), base::BindOnce(&CartService::OnOperationFinished, weak_ptr_factory_.GetWeakPtr())); } @@ -647,3 +677,43 @@ fetch_discount_worker_->Start( base::TimeDelta::FromMilliseconds(kDelayStartMs)); } + +bool CartService::IsDiscountUsed(const std::string& rule_id) { + return profile_->GetPrefs() + ->GetDictionary(prefs::kCartUsedDiscounts) + ->FindBoolKey(rule_id) != absl::nullopt; +} + +void CartService::CacheUsedDiscounts( + const cart_db::ChromeCartContentProto& proto) { + if (!proto.has_discount_info() || + proto.discount_info().discount_info().empty()) { + NOTREACHED() << "Empty discounts"; + return; + } + DictionaryPrefUpdate update(profile_->GetPrefs(), prefs::kCartUsedDiscounts); + for (auto discount_info : proto.discount_info().discount_info()) { + update->SetBoolKey(discount_info.rule_id(), true); + } +} + +void CartService::CleanUpDiscounts(cart_db::ChromeCartContentProto proto) { + if (proto.merchant_cart_url().empty()) { + NOTREACHED() << "proto does not have merchant_cart_url"; + return; + } + if (!proto.has_discount_info()) { + NOTREACHED() << "proto does not have discount_info"; + return; + } + + proto.clear_discount_info(); + cart_db_->AddCart(eTLDPlusOne(GURL(proto.merchant_cart_url())), proto, + base::BindOnce(&CartService::OnOperationFinished, + weak_ptr_factory_.GetWeakPtr())); +} + +void CartService::SetCartDiscountLinkFetcherForTesting( + std::unique_ptr<CartDiscountLinkFetcher> discount_link_fetcher) { + discount_link_fetcher_ = std::move(discount_link_fetcher); +}
diff --git a/chrome/browser/cart/cart_service.h b/chrome/browser/cart/cart_service.h index b01c569a..5038cbc 100644 --- a/chrome/browser/cart/cart_service.h +++ b/chrome/browser/cart/cart_service.h
@@ -10,6 +10,7 @@ #include "base/values.h" #include "chrome/browser/cart/cart_db.h" #include "chrome/browser/cart/cart_db_content.pb.h" +#include "chrome/browser/cart/cart_discount_link_fetcher.h" #include "chrome/browser/cart/cart_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/history/core/browser/history_service.h" @@ -54,11 +55,9 @@ void DeleteCart(const std::string& domain); // Only load carts with fake data in the database. void LoadCartsWithFakeData(CartDB::LoadCallback callback); - // Gets called when discounts are available for the given domain. - void UpdateDiscounts( - const std::string& domain, - const double timestamp, - const std::vector<cart_db::DiscountInfoProto> discount_infos); + // Gets called when discounts are available for the given cart_url. + void UpdateDiscounts(const GURL& cart_url, + cart_db::ChromeCartContentProto new_proto); // Gets called when a single cart in module is temporarily hidden. void HideCart(const GURL& cart_url, CartDB::OperationCallback callback); // Gets called when restoring the temporarily hidden single cart. @@ -95,12 +94,15 @@ // history::HistoryServiceObserver: void OnURLsDeleted(history::HistoryService* history_service, const history::DeletionInfo& deletion_info) override; + // Returns whether a discount with |rule_id| is used or not. + bool IsDiscountUsed(const std::string& rule_id); // KeyedService: void Shutdown() override; private: friend class CartServiceFactory; friend class CartServiceTest; + friend class CartServiceDiscountTest; FRIEND_TEST_ALL_PREFIXES(CartHandlerNtpModuleFakeDataTest, TestEnableFakeData); @@ -141,20 +143,29 @@ bool success, std::vector<CartDB::KeyAndValue> proto_pairs); - // A callback to handle updating discount for a cart. - void OnUpdateDiscount( - const std::string& domain, - const std::vector<cart_db::DiscountInfoProto> discount_infos, - const double timestamp, - bool success, - std::vector<CartDB::KeyAndValue> proto_pairs); // Gets called when users has enabled the rule-based discount feature. void StartGettingDiscount(); + // A callback to fetch discount URL. + void OnGetDiscountURL(const GURL& default_cart_url, + base::OnceCallback<void(const ::GURL&)> callback, + bool success, + std::vector<CartDB::KeyAndValue> proto_pairs); + // A callback to return discount URL when it is fetched. + void OnDiscountURLFetched(const GURL& default_cart_url, + base::OnceCallback<void(const ::GURL&)> callback, + const cart_db::ChromeCartContentProto& cart_proto, + const GURL& discount_url); // A callback to decide if there are partner carts. void HasPartnerCarts(base::OnceCallback<void(bool)> callback, bool success, std::vector<CartDB::KeyAndValue> proto_pairs); + // Set discount_link_fetcher_ for testing purpose. + void SetCartDiscountLinkFetcherForTesting( + std::unique_ptr<CartDiscountLinkFetcher> discount_link_fetcher); + + void CacheUsedDiscounts(const cart_db::ChromeCartContentProto& proto); + void CleanUpDiscounts(cart_db::ChromeCartContentProto proto); Profile* profile_; std::unique_ptr<CartDB> cart_db_; @@ -164,6 +175,7 @@ absl::optional<base::Value> domain_name_mapping_; absl::optional<base::Value> domain_cart_url_mapping_; std::unique_ptr<FetchDiscountWorker> fetch_discount_worker_; + std::unique_ptr<CartDiscountLinkFetcher> discount_link_fetcher_; base::WeakPtrFactory<CartService> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc index cd7ff290..b3c2387 100644 --- a/chrome/browser/cart/cart_service_unittest.cc +++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -238,6 +238,13 @@ std::move(closure).Run(); } + void GetEvaluationDiscountURL(base::OnceClosure closure, + const GURL& expected, + const GURL& found) { + EXPECT_EQ(expected, found); + std::move(closure).Run(); + } + std::string getDomainName(base::StringPiece domain) { std::string* res = service_->domain_name_mapping_->FindStringKey(domain); if (!res) @@ -253,7 +260,18 @@ return *res; } - void TearDown() override {} + void CacheUsedDiscounts(const cart_db::ChromeCartContentProto& proto) { + service_->CacheUsedDiscounts(proto); + } + + void CleanUpDiscounts(const cart_db::ChromeCartContentProto& proto) { + service_->CleanUpDiscounts(proto); + } + + void TearDown() override { + // Clean up the used discounts dictionary prefs. + profile_.GetPrefs()->ClearPref(prefs::kCartUsedDiscounts); + } protected: // This needs to be destroyed after task_environment, so that any tasks on @@ -301,7 +319,7 @@ cart_db::ChromeCartContentProto proto = BuildProto(kMockMerchantA, kMockMerchantURLA); - base::RunLoop run_loop[3]; + base::RunLoop run_loop[4]; cart_db->AddCart( kMockMerchantA, proto, base::BindOnce(&CartServiceTest::OperationEvaluation, @@ -316,20 +334,28 @@ const double timestamp = 1; - service_->UpdateDiscounts(kMockMerchantA, timestamp, kMockMerchantADiscounts); - task_environment_.RunUntilIdle(); + cart_db::ChromeCartContentProto cart_with_discount_proto = + AddDiscountToProto(proto, timestamp, kMockMerchantADiscountRuleId, + kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); - const ShoppingCarts expected = { - {kMockMerchantA, - AddDiscountToProto(proto, timestamp, kMockMerchantADiscountRuleId, - kMockMerchantADiscountsPercentOff, - kMockMerchantADiscountsRawMerchantOfferId)}}; + service_->UpdateDiscounts(GURL(kMockMerchantURLA), cart_with_discount_proto); + + const ShoppingCarts expected = {{kMockMerchantA, cart_with_discount_proto}}; cart_db->LoadCart(kMockMerchantA, base::BindOnce(&CartServiceTest::GetEvaluationDiscount, base::Unretained(this), run_loop[2].QuitClosure(), expected)); run_loop[2].Run(); + + CacheUsedDiscounts(cart_with_discount_proto); + service_->UpdateDiscounts(GURL(kMockMerchantURLA), cart_with_discount_proto); + cart_db->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationEmptyDiscount, + base::Unretained(this), run_loop[3].QuitClosure())); + run_loop[3].Run(); } // Test adding a cart with the same key and no product image won't overwrite @@ -939,6 +965,50 @@ EXPECT_EQ(GetCartURL(amazon_domain), amazon_cart.spec()); } +TEST_F(CartServiceTest, TestCacheUsedDiscounts) { + EXPECT_FALSE(service_->IsDiscountUsed(kMockMerchantADiscountRuleId)); + + cart_db::ChromeCartContentProto cart_with_discount_proto = AddDiscountToProto( + BuildProto(kMockMerchantA, kMockMerchantURLA), 1, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + + CacheUsedDiscounts(cart_with_discount_proto); + EXPECT_TRUE(service_->IsDiscountUsed(kMockMerchantADiscountRuleId)); +} + +TEST_F(CartServiceTest, TestCleanUpDiscounts) { + cart_db::ChromeCartContentProto cart_with_discount_proto = AddDiscountToProto( + BuildProto(kMockMerchantA, kMockMerchantURLA), 1, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + const ShoppingCarts has_discount_cart = { + {kMockMerchantA, cart_with_discount_proto}}; + CartDB* cart_db = service_->GetDB(); + + base::RunLoop run_loop[3]; + cart_db->AddCart( + kMockMerchantA, cart_with_discount_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + cart_db->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationDiscount, + base::Unretained(this), run_loop[1].QuitClosure(), + has_discount_cart)); + run_loop[1].Run(); + + CleanUpDiscounts(cart_with_discount_proto); + + cart_db->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationEmptyDiscount, + base::Unretained(this), run_loop[2].QuitClosure())); + run_loop[2].Run(); +} + class CartServiceFakeDataTest : public CartServiceTest { public: // Features need to be initialized before CartServiceTest::SetUp runs, in @@ -1071,6 +1141,29 @@ profile_.GetPrefs()->GetBoolean(prefs::kCartDiscountAcknowledged)); } +class MockCartDiscountLinkFetcher : public CartDiscountLinkFetcher { + public: + MOCK_METHOD( + void, + Fetch, + (std::unique_ptr<network::PendingSharedURLLoaderFactory> pending_factory, + cart_db::ChromeCartContentProto cart_content_proto, + CartDiscountLinkFetcherCallback callback), + (override)); + + void SetDiscountURL(const GURL& discount_url) { + ON_CALL(*this, Fetch) + .WillByDefault( + [discount_url]( + std::unique_ptr<network::PendingSharedURLLoaderFactory> + pending_factory, + cart_db::ChromeCartContentProto cart_content_proto, + CartDiscountLinkFetcherCallback callback) { + return std::move(callback).Run(discount_url); + }); + } +}; + class CartServiceDiscountTest : public CartServiceTest { public: // Features need to be initialized before CartServiceTest::SetUp runs, in @@ -1088,6 +1181,24 @@ // Add a partner merchant cart. service_->AddCart(kMockMerchantA, absl::nullopt, kMockProtoA); task_environment_.RunUntilIdle(); + // The feature is enabled for this test class. + profile_.GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); + } + + void TearDown() override { + // Set the feature to default disabled state after test. + profile_.GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, false); + } + + void SetCartDiscountURLForTesting(const GURL& discount_url, + bool expect_call) { + std::unique_ptr<MockCartDiscountLinkFetcher> mock_fetcher = + std::make_unique<MockCartDiscountLinkFetcher>(); + mock_fetcher->SetDiscountURL(discount_url); + if (expect_call) { + EXPECT_CALL(*mock_fetcher, Fetch); + } + service_->SetCartDiscountLinkFetcherForTesting(std::move(mock_fetcher)); } }; @@ -1151,9 +1262,128 @@ // Tests updating whether rule-based discount is enabled in profile prefs. TEST_F(CartServiceDiscountTest, TestSetCartDiscountEnabled) { - ASSERT_FALSE(profile_.GetPrefs()->GetBoolean(prefs::kCartDiscountEnabled)); - service_->SetCartDiscountEnabled(true); ASSERT_TRUE(profile_.GetPrefs()->GetBoolean(prefs::kCartDiscountEnabled)); service_->SetCartDiscountEnabled(false); ASSERT_FALSE(profile_.GetPrefs()->GetBoolean(prefs::kCartDiscountEnabled)); + service_->SetCartDiscountEnabled(true); + ASSERT_TRUE(profile_.GetPrefs()->GetBoolean(prefs::kCartDiscountEnabled)); +} + +// Tests no fetching for discount URL if the cart is not from a partner +// merchant. +TEST_F(CartServiceDiscountTest, TestNoFetchForNonPartner) { + base::RunLoop run_loop[2]; + const double timestamp = 1; + SetCartDiscountURLForTesting(GURL("https://www.discount.com"), false); + cart_db::ChromeCartContentProto cart_proto = AddDiscountToProto( + BuildProto(kMockMerchantB, kMockMerchantURLB), timestamp, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + service_->GetDB()->AddCart( + kMockMerchantB, cart_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + GURL default_cart_url(kMockMerchantURLB); + service_->GetDiscountURL( + default_cart_url, + base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL, + base::Unretained(this), run_loop[1].QuitClosure(), + default_cart_url)); + run_loop[1].Run(); +} + +// Tests no fetching for discount URL if the cart doesn't have discount info. +TEST_F(CartServiceDiscountTest, TestNoFetchWhenNoDiscount) { + base::RunLoop run_loop[2]; + SetCartDiscountURLForTesting(GURL("https://www.discount.com"), false); + service_->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationEmptyDiscount, + base::Unretained(this), run_loop[0].QuitClosure())); + run_loop[0].Run(); + + GURL default_cart_url(kMockMerchantURLA); + service_->GetDiscountURL( + default_cart_url, + base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL, + base::Unretained(this), run_loop[1].QuitClosure(), + default_cart_url)); + run_loop[1].Run(); +} + +// Tests no fetching for discount URL if the feature is disabled. +TEST_F(CartServiceDiscountTest, TestNoFetchWhenFeatureDisabled) { + base::RunLoop run_loop[2]; + const double timestamp = 1; + GURL discount_url("https://www.discount.com"); + SetCartDiscountURLForTesting(discount_url, false); + profile_.GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, false); + cart_db::ChromeCartContentProto cart_proto = AddDiscountToProto( + BuildProto(kMockMerchantA, kMockMerchantURLA), timestamp, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + service_->GetDB()->AddCart( + kMockMerchantA, cart_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + GURL default_cart_url(kMockMerchantURLA); + service_->GetDiscountURL( + default_cart_url, + base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL, + base::Unretained(this), run_loop[1].QuitClosure(), + default_cart_url)); + run_loop[1].Run(); +} + +// Tests CartService returning fetched discount URL. +TEST_F(CartServiceDiscountTest, TestReturnDiscountURL) { + base::RunLoop run_loop[2]; + const double timestamp = 1; + GURL discount_url("https://www.discount.com"); + SetCartDiscountURLForTesting(discount_url, true); + cart_db::ChromeCartContentProto cart_proto = AddDiscountToProto( + BuildProto(kMockMerchantA, kMockMerchantURLA), timestamp, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + service_->GetDB()->AddCart( + kMockMerchantA, cart_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + service_->GetDiscountURL( + GURL(kMockMerchantURLA), + base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL, + base::Unretained(this), run_loop[1].QuitClosure(), + discount_url)); + run_loop[1].Run(); +} + +// Tests CartService returning original cart URL as a fallback if the fetch +// response is invalid. +TEST_F(CartServiceDiscountTest, TestFetchInvalidFallback) { + base::RunLoop run_loop[2]; + const double timestamp = 1; + SetCartDiscountURLForTesting(GURL("error"), true); + cart_db::ChromeCartContentProto cart_proto = AddDiscountToProto( + BuildProto(kMockMerchantA, kMockMerchantURLA), timestamp, + kMockMerchantADiscountRuleId, kMockMerchantADiscountsPercentOff, + kMockMerchantADiscountsRawMerchantOfferId); + service_->GetDB()->AddCart( + kMockMerchantA, cart_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + GURL default_cart_url(kMockMerchantURLA); + service_->GetDiscountURL( + default_cart_url, + base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL, + base::Unretained(this), run_loop[1].QuitClosure(), + default_cart_url)); + run_loop[1].Run(); }
diff --git a/chrome/browser/cart/commerce_hint_service.cc b/chrome/browser/cart/commerce_hint_service.cc index 79654161..fb18e7b31 100644 --- a/chrome/browser/cart/commerce_hint_service.cc +++ b/chrome/browser/cart/commerce_hint_service.cc
@@ -15,15 +15,23 @@ #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "components/search/ntp_features.h" #include "content/public/browser/frame_service_base.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "third_party/re2/src/re2/re2.h" namespace cart { namespace { +// TODO(crbug.com/1207197): Pull below methods to a utility class to share with +// other classes. +constexpr base::FeatureParam<std::string> kPartnerMerchantPattern{ + &ntp_features::kNtpChromeCartModule, "partner-merchant-pattern", + // This regex does not match anything. + "\\b\\B"}; // TODO(crbug/1164236): support multiple cart systems in the same domain. // Returns eTLB+1 domain. @@ -32,6 +40,21 @@ url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); } +const re2::RE2& GetPartnerMerchantPattern() { + re2::RE2::Options options; + options.set_case_sensitive(false); + static base::NoDestructor<re2::RE2> instance(kPartnerMerchantPattern.Get(), + options); + return *instance; +} + +bool IsPartnerMerchant(const GURL& url) { + const std::string& url_string = url.spec(); + return RE2::PartialMatch( + re2::StringPiece(url_string.data(), url_string.size()), + GetPartnerMerchantPattern()); +} + void ConstructCartProto(cart_db::ChromeCartContentProto* proto, const GURL& navigation_url, std::vector<mojom::ProductPtr> products) { @@ -170,6 +193,12 @@ DVLOG(1) << "Reject cart URL with different eTLD+1 domain."; validated_cart = absl::nullopt; } + // When rule-based discount is enabled, do not accept cart page URLs from + // partner merchants as there could be things like discount tokens in them. + if (service_->IsCartDiscountEnabled() && IsPartnerMerchant(navigation_url) && + product_id.empty()) { + validated_cart = absl::nullopt; + } cart_db::ChromeCartContentProto proto; std::vector<mojom::ProductPtr> products; if (!product_id.empty()) { @@ -191,9 +220,15 @@ std::vector<mojom::ProductPtr> products) { if (ShouldSkip(cart_url)) return; + absl::optional<GURL> validated_cart = cart_url; + // When rule-based discount is enabled, do not accept cart page URLs from + // partner merchants as there could be things like discount tokens in them. + if (service_->IsCartDiscountEnabled() && IsPartnerMerchant(cart_url)) { + validated_cart = absl::nullopt; + } cart_db::ChromeCartContentProto proto; ConstructCartProto(&proto, cart_url, std::move(products)); - service_->AddCart(proto.key(), cart_url, std::move(proto)); + service_->AddCart(proto.key(), validated_cart, std::move(proto)); } WEB_CONTENTS_USER_DATA_KEY_IMPL(CommerceHintService)
diff --git a/chrome/browser/cart/fetch_discount_worker.cc b/chrome/browser/cart/fetch_discount_worker.cc index 36929ea5..13b44d9b 100644 --- a/chrome/browser/cart/fetch_discount_worker.cc +++ b/chrome/browser/cart/fetch_discount_worker.cc
@@ -17,12 +17,6 @@ // 30 minutes. const int64_t kDelayFetchMs = 1800000; const int kImmediateFetchMs = 0; - -std::string eTLDPlusOne(const GURL& url) { - return net::registry_controlled_domains::GetDomainAndRegistry( - url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); -} - } // namespace CartLoader::CartLoader(Profile* profile) @@ -42,9 +36,8 @@ void CartDiscountUpdater::update( const std::string& cart_url, const cart_db::ChromeCartContentProto new_proto) { - const GURL url(cart_url); - std::string domain = eTLDPlusOne(url); - cart_service_->AddCart(domain, url, std::move(new_proto)); + GURL url(cart_url); + cart_service_->UpdateDiscounts(url, std::move(new_proto)); } CartLoaderAndUpdaterFactory::CartLoaderAndUpdaterFactory(Profile* profile)
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 4020633..e57f43f 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -104,7 +104,7 @@ #include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom.h" #include "third_party/blink/public/mojom/installedapp/installed_app_provider.mojom.h" #else -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/badging/badge_manager.h" #include "chrome/browser/cart/chrome_cart.mojom.h" #include "chrome/browser/cart/commerce_hint_service.h" @@ -492,7 +492,8 @@ PrefService* profile_prefs = profile->GetPrefs(); if (profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled) && media::IsLiveCaptionFeatureEnabled()) { - captions::CaptionHostImpl::Create(frame_host, std::move(receiver)); + captions::LiveCaptionSpeechRecognitionHost::Create(frame_host, + std::move(receiver)); } } #endif
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 4b75f87..37412fa 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1319,6 +1319,8 @@ registry->RegisterListPref( site_isolation::prefs::kUserTriggeredIsolatedOrigins); registry->RegisterDictionaryPref( + site_isolation::prefs::kWebTriggeredIsolatedOrigins); + registry->RegisterDictionaryPref( prefs::kDevToolsBackgroundServicesExpirationDict); registry->RegisterBooleanPref(prefs::kSignedHTTPExchangeEnabled, true); #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc index 096134247..e1f39b7 100644 --- a/chrome/browser/chrome_navigation_browsertest.cc +++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -2422,3 +2422,212 @@ ->GetProcess() ->IsProcessLockedToSiteForTesting()); } + +// This test class turns on the mode where sites served with +// Cross-Origin-Opener-Policy headers are site-isolated. This complements +// COOPIsolationTest in content_browsertests and focuses on persistence of COOP +// sites in user prefs, which requires the //chrome layer. +class SiteIsolationForCOOPBrowserTest : public ChromeNavigationBrowserTest { + public: + // Use an HTTP server, since the COOP header is only populated for HTTPS. + SiteIsolationForCOOPBrowserTest() + : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { + // Enable COOP isolation with a max of 3 stored sites. + const std::vector<base::test::ScopedFeatureList::FeatureAndParams> + kEnabledFeatures = { + {::features::kSiteIsolationForCrossOriginOpenerPolicy, + {{"stored_sites_max_size", base::NumberToString(3)}, + {"should_persist_across_restarts", "true"}}}}; + // Disable full site isolation so we can observe effects of COOP isolation. + const std::vector<base::Feature> kDisabledFeatures = { + features::kSitePerProcess}; + feature_list_.InitWithFeaturesAndParameters(kEnabledFeatures, + kDisabledFeatures); + } + + // Returns the list of COOP sites currently stored in user prefs. + std::vector<std::string> GetSavedIsolatedSites(Profile* profile) { + PrefService* prefs = profile->GetPrefs(); + auto* dict = prefs->GetDictionary( + site_isolation::prefs::kWebTriggeredIsolatedOrigins); + std::vector<std::string> sites; + for (const auto& site_time_pair : dict->DictItems()) + sites.push_back(site_time_pair.first); + return sites; + } + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + ChromeNavigationBrowserTest::SetUpCommandLine(command_line); + + // Allow HTTPS server to be used on sites other than localhost. + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); + } + + void SetUp() override { + https_server_.AddDefaultHandlers(GetChromeTestDataDir()); + ASSERT_TRUE(https_server_.InitializeAndListen()); + ChromeNavigationBrowserTest::SetUp(); + } + + void SetUpOnMainThread() override { + https_server_.StartAcceptingConnections(); + ChromeNavigationBrowserTest::SetUpOnMainThread(); + } + + net::EmbeddedTestServer* https_server() { return &https_server_; } + + private: + base::test::ScopedFeatureList feature_list_; + net::EmbeddedTestServer https_server_; +}; + +// Verifies that sites isolated due to COOP headers are persisted across +// restarts. Note that persistence requires both visiting the COOP site and +// interacting with it via a user activation. Part 1/2. +IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, + PRE_PersistAcrossRestarts) { + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), IsEmpty()); + + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + // Navigate to a couple of URLs with COOP and trigger user activation on each + // one to add them to the saved list in user prefs. + GURL coop_url = https_server()->GetURL( + "saved.com", "/set-header?Cross-Origin-Opener-Policy: same-origin"); + GURL coop_url2 = https_server()->GetURL( + "saved2.com", "/set-header?Cross-Origin-Opener-Policy: same-origin"); + ui_test_utils::NavigateToURL(browser(), coop_url); + // Simulate user activation. + EXPECT_TRUE(ExecJs(contents, "// no-op")); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + ui_test_utils::NavigateToURL(browser(), coop_url2); + // Simulate user activation. + EXPECT_TRUE(ExecJs(contents, "// no-op")); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + // Check that saved.com and saved2.com were saved to disk. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), + UnorderedElementsAre("https://saved.com", "https://saved2.com")); +} + +// Verifies that sites isolated due to COOP headers with a user activation are +// persisted across restarts. Part 2/2. +IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, PersistAcrossRestarts) { + // Check that saved.com and saved2.com are still saved after a restart. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), + UnorderedElementsAre("https://saved.com", "https://saved2.com")); + + // Check that these sites have been loaded as isolated on startup and utilize + // a dedicated process after restarting even without serving COOP headers. + GURL saved_url(https_server()->GetURL("saved.com", "/title1.html")); + GURL saved2_url(https_server()->GetURL("saved2.com", "/title2.html")); + ui_test_utils::NavigateToURL(browser(), saved_url); + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + ui_test_utils::NavigateToURL(browser(), saved2_url); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + // Sanity check that an unrelated non-isolated foo.com URL does not require a + // dedicated process. + GURL foo_url(https_server()->GetURL("foo.com", "/title3.html")); + ui_test_utils::NavigateToURL(browser(), foo_url); + EXPECT_FALSE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); +} + +// Check that COOP sites are not persisted in Incognito; the isolation should +// only persist for the duration of the Incognito session. +IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, Incognito) { + Browser* incognito = CreateIncognitoBrowser(); + + GURL coop_url = https_server()->GetURL( + "foo.com", "/set-header?Cross-Origin-Opener-Policy: same-origin"); + + ui_test_utils::NavigateToURL(incognito, coop_url); + content::WebContents* contents = + incognito->tab_strip_model()->GetActiveWebContents(); + // Simulate user activation to isolate foo.com for the rest of the incognito + // session. + EXPECT_TRUE(ExecJs(contents, "// no-op")); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + // Check that navigations to foo.com (even without COOP) are isolated in + // future BrowsingInstances in Incognito. + AddBlankTabAndShow(incognito); + GURL foo_url = https_server()->GetURL("foo.com", "/title1.html"); + ui_test_utils::NavigateToURL(incognito, foo_url); + contents = incognito->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + // foo.com should not be isolated in the regular profile. + AddBlankTabAndShow(browser()); + ui_test_utils::NavigateToURL(browser(), foo_url); + contents = browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_FALSE( + contents->GetMainFrame()->GetSiteInstance()->RequiresDedicatedProcess()); + + // Neither profile should've saved foo.com to COOP isolated sites prefs. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), IsEmpty()); + EXPECT_THAT(GetSavedIsolatedSites(incognito->profile()), IsEmpty()); +} + +// Verify that when a COOP-isolated site is visited again, the timestamp in its +// stored pref entry is updated correctly and taken into consideration when +// trimming the list of stored COOP sites to its maximum size. +IN_PROC_BROWSER_TEST_F(SiteIsolationForCOOPBrowserTest, + TimestampUpdateOnSecondVisit) { + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), IsEmpty()); + + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + const std::string kCoopPath = + "/set-header?Cross-Origin-Opener-Policy: same-origin"; + GURL coop1 = https_server()->GetURL("coop1.com", kCoopPath); + GURL coop2 = https_server()->GetURL("coop2.com", kCoopPath); + GURL coop3 = https_server()->GetURL("coop3.com", kCoopPath); + GURL coop4 = https_server()->GetURL("coop4.com", kCoopPath); + + // Navigate to three COOP sites and trigger user actuvation on each one to + // add them all to the list of persistently isolated COOP sites. + ui_test_utils::NavigateToURL(browser(), coop1); + EXPECT_TRUE(ExecJs(contents, "// no-op")); // Simulate user activation. + ui_test_utils::NavigateToURL(browser(), coop2); + EXPECT_TRUE(ExecJs(contents, "// no-op")); // Simulate user activation. + ui_test_utils::NavigateToURL(browser(), coop3); + EXPECT_TRUE(ExecJs(contents, "// no-op")); // Simulate user activation. + + // At this point, the first three sites should be saved to prefs. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), + UnorderedElementsAre("https://coop1.com", "https://coop2.com", + "https://coop3.com")); + + // Visit coop1.com again. This should update its timestamp to be more recent + // than coop2.com and coop3.com. The set of saved sites shouldn't change. + AddBlankTabAndShow(browser()); + contents = browser()->tab_strip_model()->GetActiveWebContents(); + ui_test_utils::NavigateToURL(browser(), coop1); + EXPECT_TRUE(ExecJs(contents, "// no-op")); // Simulate user activation. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), + UnorderedElementsAre("https://coop1.com", "https://coop2.com", + "https://coop3.com")); + + // Now, visit coop4.com. Since the maximum number of saved COOP sites is 3 + // in this test, the oldest site should be evicted. That evicted site should + // be coop2.com, since coop1.com's timestamp was just updated. + ui_test_utils::NavigateToURL(browser(), coop4); + EXPECT_TRUE(ExecJs(contents, "// no-op")); // Simulate user activation. + EXPECT_THAT(GetSavedIsolatedSites(browser()->profile()), + UnorderedElementsAre("https://coop1.com", "https://coop3.com", + "https://coop4.com")); +}
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index ac0359b..e5a4ce48 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -498,8 +498,6 @@ "../ash/accessibility/magnifier_type.h", "../ash/accessibility/select_to_speak_event_handler_delegate_impl.cc", "../ash/accessibility/select_to_speak_event_handler_delegate_impl.h", - "../ash/accessibility/soda_installer_impl_chromeos.cc", - "../ash/accessibility/soda_installer_impl_chromeos.h", "../ash/account_manager/account_manager_edu_coexistence_controller.cc", "../ash/account_manager/account_manager_edu_coexistence_controller.h", "../ash/account_manager/account_manager_facade_factory_ash.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index 18c415748..3bcb133a 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -173,6 +173,7 @@ #include "ui/display/screen.h" #include "ui/events/event_constants.h" #include "ui/events/types/event_type.h" +#include "ui/gfx/geometry/point_conversions.h" #include "ui/message_center/message_center.h" #include "ui/message_center/notification_list.h" #include "ui/message_center/public/cpp/notification.h" @@ -953,13 +954,13 @@ ~EventGenerator() = default; void ScheduleMouseEvent(ui::EventType type, - gfx::PointF location_in_host, + gfx::PointF location_in_screen, int flags) { if (flags == 0 && (type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED)) { LOG(ERROR) << "No flags specified for mouse button changes"; } - tasks_.push_back(Task(type, location_in_host, flags)); + tasks_.push_back(Task(type, location_in_screen, flags)); } void Run() { @@ -977,12 +978,12 @@ }; const ui::EventType type; - const gfx::PointF location_in_host; + const gfx::PointF location_in_screen; const int flags; Status status = kNotScheduled; - Task(ui::EventType type, gfx::PointF location_in_host, int flags) - : type(type), location_in_host(location_in_host), flags(flags) {} + Task(ui::EventType type, gfx::PointF location_in_screen, int flags) + : type(type), location_in_screen(location_in_screen), flags(flags) {} }; void SendEvent() { @@ -1017,14 +1018,32 @@ } break; } - case ui::ET_MOUSE_MOVED: - case ui::ET_MOUSE_DRAGGED: + case ui::ET_MOUSE_MOVED: { + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestPoint( + gfx::ToFlooredPoint((task->location_in_screen))); + auto* root_window = ash::Shell::GetRootWindowForDisplayId(display.id()); + if (!root_window->GetBoundsInScreen().Contains( + gfx::ToFlooredPoint(task->location_in_screen))) { + // Not in any of the display. Does nothing and schedules a new task. + OnFinishedProcessingEvent(); + return; + } + gfx::PointF location_in_host(task->location_in_screen); + wm::ConvertPointFromScreen(root_window, &location_in_host); + ConvertPointToHost(root_window, &location_in_host); + if (root_window->GetHost() != host_) { + // Switching to the new display. + host_ = root_window->GetHost(); + host_->MoveCursorToLocationInPixels( + gfx::ToFlooredPoint(location_in_host)); + } // The location should be offset by the origin of the root-window since // ui::SystemInputInjector expects so. input_injector_->MoveCursorTo( - task->location_in_host + - host_->GetBoundsInPixels().OffsetFromOrigin()); + location_in_host + host_->GetBoundsInPixels().OffsetFromOrigin()); break; + } default: NOTREACHED(); } @@ -4469,38 +4488,30 @@ if (!root_window) return RespondNow(Error("Failed to find the root window")); - const gfx::PointF location_in_root(params->location.x, params->location.y); - gfx::PointF location_in_screen = location_in_root; - wm::ConvertPointToScreen(root_window, &location_in_screen); + gfx::Point location_in_screen(params->location.x, params->location.y); auto* env = aura::Env::GetInstance(); const gfx::Point last_mouse_location(env->last_mouse_location()); - if (last_mouse_location == gfx::ToFlooredPoint(location_in_screen)) + if (last_mouse_location == location_in_screen) return RespondNow(NoArguments()); - gfx::PointF location_in_host = location_in_root; - ConvertPointToHost(root_window, &location_in_host); - event_generator_ = std::make_unique<EventGenerator>( root_window->GetHost(), base::BindOnce(&AutotestPrivateMouseMoveFunction::Respond, this, NoArguments())); - gfx::PointF start_in_host(last_mouse_location.x(), last_mouse_location.y()); - wm::ConvertPointFromScreen(root_window, &start_in_host); - ConvertPointToHost(root_window, &start_in_host); int64_t steps = std::max( base::ClampFloor<int64_t>(params->duration_in_ms / event_generator_->interval().InMillisecondsF()), static_cast<int64_t>(1)); int flags = env->mouse_button_flags(); - ui::EventType type = (flags == 0) ? ui::ET_MOUSE_MOVED : ui::ET_MOUSE_DRAGGED; for (int64_t i = 1; i <= steps; ++i) { double progress = static_cast<double>(i) / static_cast<double>(steps); - gfx::PointF point(gfx::Tween::FloatValueBetween(progress, start_in_host.x(), - location_in_host.x()), - gfx::Tween::FloatValueBetween(progress, start_in_host.y(), - location_in_host.y())); - event_generator_->ScheduleMouseEvent(type, point, flags); + gfx::PointF point( + gfx::Tween::FloatValueBetween(progress, last_mouse_location.x(), + location_in_screen.x()), + gfx::Tween::FloatValueBetween(progress, last_mouse_location.y(), + location_in_screen.y())); + event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_MOVED, point, flags); } event_generator_->Run(); return RespondLater(); @@ -5113,12 +5124,10 @@ if (!event_router) return; - std::unique_ptr<base::ListValue> event_args = - std::make_unique<base::ListValue>(); std::unique_ptr<Event> event( new Event(events::AUTOTESTPRIVATE_ON_CLIPBOARD_DATA_CHANGED, api::autotest_private::OnClipboardDataChanged::kEventName, - std::move(event_args))); + std::vector<base::Value>())); event_router->BroadcastEvent(std::move(event)); }
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc index 647796a1..94133aff 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -151,184 +151,183 @@ }; IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Mount) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/mount", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/mount", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Unmount) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/unmount", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/unmount", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, GetAll) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/get_all", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/get_all", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, GetMetadata) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/get_metadata", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/get_metadata", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, ReadDirectory) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/read_directory", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/read_directory", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, ReadFile) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/read_file", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/read_file", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, BigFile) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/big_file", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/big_file", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Evil) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/evil", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/evil", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, MimeType) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/mime_type", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/mime_type", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, CreateDirectory) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/create_directory", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/create_directory", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, DeleteEntry) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/delete_entry", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/delete_entry", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, CreateFile) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/create_file", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/create_file", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, CopyEntry) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/copy_entry", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/copy_entry", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, MoveEntry) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/move_entry", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/move_entry", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Truncate) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/truncate", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/truncate", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, WriteFile) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/write_file", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/write_file", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Extension) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/extension"}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/extension", {}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Thumbnail) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/thumbnail", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/thumbnail", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, AddWatcher) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/add_watcher", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/add_watcher", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, RemoveWatcher) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/remove_watcher", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/remove_watcher", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Notify) { - ASSERT_TRUE(RunExtensionTest( - {.name = "file_system_provider/notify", .launch_as_platform_app = true}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/notify", + {.launch_as_platform_app = true}, + {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Configure) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/configure", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/configure", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, GetActions) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/get_actions", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/get_actions", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, ExecuteAction) { - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/execute_action", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/execute_action", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Unresponsive_Extension) { AbortOnUnresponsivePerformer performer(browser()->profile()); - ASSERT_TRUE( - RunExtensionTest({.name = "file_system_provider/unresponsive_extension"}, - {.load_as_component = true})) + ASSERT_TRUE(RunExtensionTest("file_system_provider/unresponsive_extension", + {}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, Unresponsive_App) { AbortOnUnresponsivePerformer performer(browser()->profile()); - ASSERT_TRUE(RunExtensionTest({.name = "file_system_provider/unresponsive_app", - .launch_as_platform_app = true}, + ASSERT_TRUE(RunExtensionTest("file_system_provider/unresponsive_app", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; }
diff --git a/chrome/browser/chromeos/extensions/media_player_event_router.cc b/chrome/browser/chromeos/extensions/media_player_event_router.cc index 05d2dc4..071a6090 100644 --- a/chrome/browser/chromeos/extensions/media_player_event_router.cc +++ b/chrome/browser/chromeos/extensions/media_player_event_router.cc
@@ -19,9 +19,8 @@ events::HistogramValue histogram_value, const std::string& event_name) { if (context && EventRouter::Get(context)) { - std::unique_ptr<base::ListValue> args(new base::ListValue()); std::unique_ptr<Event> event( - new Event(histogram_value, event_name, std::move(args))); + new Event(histogram_value, event_name, std::vector<base::Value>())); EventRouter::Get(context)->BroadcastEvent(std::move(event)); } }
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper_api.cc index ab97650..9ffa3d6 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_api.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_api.cc
@@ -204,11 +204,11 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile); - base::Value event_args(Value::Type::LIST); - event_args.Append(Value(GenerateThumbnail(image, image.size()))); - event_args.Append(Value(thumbnail_data)); - event_args.Append( - extensions::api::wallpaper::ToString(params_->details.layout)); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(GenerateThumbnail(image, image.size()))); + event_args.push_back(base::Value(thumbnail_data)); + event_args.push_back(base::Value( + extensions::api::wallpaper::ToString(params_->details.layout))); // Setting wallpaper from right click menu in 'Files' app is a feature that // was implemented in crbug.com/578935. Since 'Files' app is a built-in v1 // app in ChromeOS, we should treat it slightly differently with other third @@ -216,14 +216,15 @@ // and it should not appear in the wallpaper grid in the Wallpaper Picker. // But we should not display the 'wallpaper-set-by-mesage' since it might // introduce confusion as shown in crbug.com/599407. - event_args.Append((extension()->id() == file_manager::kFileManagerAppId) - ? base::StringPiece() - : extension()->name()); + base::StringPiece ext_name; + if (extension()->id() != file_manager::kFileManagerAppId) + ext_name = extension()->name(); + event_args.push_back(base::Value(ext_name)); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events::WALLPAPER_PRIVATE_ON_WALLPAPER_CHANGED_BY_3RD_PARTY, extensions::api::wallpaper_private::OnWallpaperChangedBy3rdParty:: kEventName, - base::ListValue::From(std::make_unique<Value>(std::move(event_args))))); + std::move(event_args))); event_router->DispatchEventToExtension(extension_misc::kWallpaperManagerId, std::move(event)); }
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc index 5345dab7..6b35928c 100644 --- a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc +++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc
@@ -36,7 +36,11 @@ absl::optional<double> scale_factor = GetDisplayScaleFactor(display_id); DCHECK(scale_factor.has_value()); - uint32_t theme_color = color.has_value() ? color.value() : SK_ColorWHITE; + // TODO(sstan): Fallback to system default color or other topic color, if + // the task hasn't valid theme color. + uint32_t theme_color = color.has_value() && IsValidThemeColor(color.value()) + ? color.value() + : SK_ColorWHITE; // TODO(sstan): Handle the desk container from full_restore data. int container = ash::desks_util::GetActiveDeskContainerId();
diff --git a/chrome/browser/chromeos/full_restore/arc_window_utils.cc b/chrome/browser/chromeos/full_restore/arc_window_utils.cc index a009ce1e..7490f57d 100644 --- a/chrome/browser/chromeos/full_restore/arc_window_utils.cc +++ b/chrome/browser/chromeos/full_restore/arc_window_utils.cc
@@ -7,6 +7,7 @@ #include "ash/public/cpp/ash_features.h" #include "components/arc/arc_util.h" #include "components/exo/wm_helper.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -65,5 +66,9 @@ return window_info; } +bool IsValidThemeColor(uint32_t theme_color) { + return SkColorGetA(theme_color) == SK_AlphaOPAQUE; +} + } // namespace full_restore } // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/arc_window_utils.h b/chrome/browser/chromeos/full_restore/arc_window_utils.h index ee2e3d3..c5b06c2 100644 --- a/chrome/browser/chromeos/full_restore/arc_window_utils.h +++ b/chrome/browser/chromeos/full_restore/arc_window_utils.h
@@ -27,6 +27,10 @@ apps::mojom::WindowInfoPtr HandleArcWindowInfo( apps::mojom::WindowInfoPtr window_info); +// Returns true if it is a valid theme color. In Android, any transparent color +// cannot be a topic color. +bool IsValidThemeColor(uint32_t theme_color); + } // namespace full_restore } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printer_setup_util.cc b/chrome/browser/chromeos/printing/printer_setup_util.cc index a78c7fe..50ee4ac9 100644 --- a/chrome/browser/chromeos/printing/printer_setup_util.cc +++ b/chrome/browser/chromeos/printing/printer_setup_util.cc
@@ -110,15 +110,39 @@ void CapabilitiesFetchedFromService( const std::string& printer_id, + bool elevated_privileges, GetPrinterCapabilitiesCallback cb, mojom::PrinterSemanticCapsAndDefaultsResultPtr printer_caps) { if (printer_caps->is_result_code()) { LOG(WARNING) << "Failure fetching printer capabilities from service for " << printer_id << " - error " << printer_caps->get_result_code(); + + // If we failed because of access denied then we could retry at an elevated + // privilege (if not already elevated). + if (printer_caps->get_result_code() == mojom::ResultCode::kAccessDenied && + !elevated_privileges) { + // Register that this printer requires elevated privileges. + PrintBackendServiceManager& service_mgr = + PrintBackendServiceManager::GetInstance(); + service_mgr.SetPrinterDriverRequiresElevatedPrivilege(printer_id); + + // Retry the operation which should now happen at a higher privilege + // level. + auto& service = service_mgr.GetService( + g_browser_process->GetApplicationLocale(), printer_id); + service->GetPrinterSemanticCapsAndDefaults( + printer_id, + base::BindOnce(&CapabilitiesFetchedFromService, printer_id, + /*elevated_privileges=*/true, std::move(cb))); + return; + } + + // Unable to fallback, call back without data. std::move(cb).Run(absl::nullopt); return; } + VLOG(1) << "Successfully received printer capabilities from service for " << printer_id; std::move(cb).Run(printer_caps->get_printer_caps()); @@ -130,11 +154,16 @@ if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) { VLOG(1) << "Fetching printer capabilities via service"; - auto& service = PrintBackendServiceManager::GetInstance().GetService( + PrintBackendServiceManager& service_mgr = + PrintBackendServiceManager::GetInstance(); + auto& service = service_mgr.GetService( g_browser_process->GetApplicationLocale(), printer_id); service->GetPrinterSemanticCapsAndDefaults( - printer_id, base::BindOnce(&CapabilitiesFetchedFromService, printer_id, - std::move(cb))); + printer_id, + base::BindOnce( + &CapabilitiesFetchedFromService, printer_id, + service_mgr.PrinterDriverRequiresElevatedPrivilege(printer_id), + std::move(cb))); } else { VLOG(1) << "Fetching printer capabilities in-process"; // USER_VISIBLE because the result is displayed in the print preview dialog.
diff --git a/chrome/browser/commerce/subscriptions/android/BUILD.gn b/chrome/browser/commerce/subscriptions/android/BUILD.gn index 7c8128c..c844a1a8 100644 --- a/chrome/browser/commerce/subscriptions/android/BUILD.gn +++ b/chrome/browser/commerce/subscriptions/android/BUILD.gn
@@ -4,35 +4,6 @@ import("//build/config/android/rules.gni") -android_library("java") { - sources = [ - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscription.java", - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionJsonSerializer.java", - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceConfig.java", - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java", - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java", - "java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java", - "java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java", - "java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java", - ] - - deps = [ - "//base:base_java", - "//chrome/android:base_module_java", - "//chrome/browser/android/lifecycle:java", - "//chrome/browser/endpoint_fetcher:java", - "//chrome/browser/flags:java", - "//chrome/browser/preferences:java", - "//chrome/browser/profiles/android:java", - "//chrome/browser/tab:java", - "//chrome/browser/tabmodel:java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//url:gurl_java", - ] - - annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] -} - generate_jni("jni_headers") { sources = [ "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscription.java",
diff --git a/chrome/browser/commerce/subscriptions/android/DEPS b/chrome/browser/commerce/subscriptions/android/DEPS index ff761be..3d12816 100644 --- a/chrome/browser/commerce/subscriptions/android/DEPS +++ b/chrome/browser/commerce/subscriptions/android/DEPS
@@ -1,3 +1,4 @@ include_rules = [ + "+chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingUtilities.java", "+chrome/android/java/src/org/chromium/chrome/browser", ] \ No newline at end of file
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java new file mode 100644 index 0000000..e9afc28 --- /dev/null +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java
@@ -0,0 +1,44 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.subscriptions; + +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; + +/** + * Commerce Subscriptions Service. + */ +public class CommerceSubscriptionsService { + private final SubscriptionsManagerImpl mSubscriptionManager; + private ImplicitPriceDropSubscriptionsManager mImplicitPriceDropSubscriptionsManager; + + /** Creates a new instance. */ + CommerceSubscriptionsService(SubscriptionsManagerImpl subscriptionsManager) { + mSubscriptionManager = subscriptionsManager; + } + + /** Performs any deferred startup tasks required by {@link Subscriptions}. */ + public void initDeferredStartupForActivity(TabModelSelector tabModelSelector, + ActivityLifecycleDispatcher activityLifecycleDispatcher) { + if (mImplicitPriceDropSubscriptionsManager == null) { + mImplicitPriceDropSubscriptionsManager = new ImplicitPriceDropSubscriptionsManager( + tabModelSelector, activityLifecycleDispatcher, mSubscriptionManager); + } + } + + /** Returns the subscriptionsManager. */ + public SubscriptionsManagerImpl getSubscriptionsManager() { + return mSubscriptionManager; + } + + /** + * Cleans up internal resources. Currently this method calls SubscriptionsManagerImpl#destroy. + */ + public void destroy() { + if (mImplicitPriceDropSubscriptionsManager != null) { + mImplicitPriceDropSubscriptionsManager.destroy(); + } + } +}
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactory.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactory.java new file mode 100644 index 0000000..dcadd88 --- /dev/null +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactory.java
@@ -0,0 +1,67 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.subscriptions; + +import androidx.annotation.VisibleForTesting; + +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.profiles.ProfileManager; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link CommerceSubscriptionsService} cached by {@link Profile}. + */ +public class CommerceSubscriptionsServiceFactory { + @VisibleForTesting + protected static final Map<Profile, CommerceSubscriptionsService> + sProfileToSubscriptionsService = new HashMap<>(); + private static ProfileManager.Observer sProfileManagerObserver; + + /** Creates new instance. */ + public CommerceSubscriptionsServiceFactory() { + if (sProfileManagerObserver == null) { + sProfileManagerObserver = new ProfileManager.Observer() { + @Override + public void onProfileAdded(Profile profile) {} + + @Override + public void onProfileDestroyed(Profile destroyedProfile) { + CommerceSubscriptionsService serviceToDestroy = + sProfileToSubscriptionsService.get(destroyedProfile); + if (serviceToDestroy != null) { + serviceToDestroy.destroy(); + sProfileToSubscriptionsService.remove(destroyedProfile); + } + + if (sProfileToSubscriptionsService.isEmpty()) { + ProfileManager.removeObserver(sProfileManagerObserver); + sProfileManagerObserver = null; + } + } + }; + ProfileManager.addObserver(sProfileManagerObserver); + } + } + + /** + * Creates a new instance or reuses an existing one based on the current {@link Profile}. + * + * Note: Don't hold a reference to the returned value. Always use this method to access {@link + * CommerceSubscriptionsService} instead. + * @return {@link CommerceSubscriptionsService} instance for the current regular + * profile. + */ + public CommerceSubscriptionsService getForLastUsedProfile() { + Profile profile = Profile.getLastUsedRegularProfile(); + CommerceSubscriptionsService service = sProfileToSubscriptionsService.get(profile); + if (service == null) { + service = new CommerceSubscriptionsService(new SubscriptionsManagerImpl(profile)); + sProfileToSubscriptionsService.put(profile, service); + } + return service; + } +}
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java index 136470d..4395558 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java
@@ -16,7 +16,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; - /** * Wrapper around CommerceSubscriptions Web APIs. */ @@ -41,6 +40,15 @@ private static final String GET_SUBSCRIPTIONS_QUERY_PARAMS_TEMPLATE = "?requestParams.subscriptionType=%s"; private static final int BACKEND_CANONICAL_CODE_SUCCESS = 0; + private final Profile mProfile; + + /** + * Creates a new instance. + * @param profile the {@link Profile} to use when making the calls. + */ + public CommerceSubscriptionsServiceProxy(Profile profile) { + mProfile = profile; + } /** * Makes an HTTPS call to the backend in order to create the provided subscriptions. @@ -67,13 +75,12 @@ */ public void get(@CommerceSubscription.CommerceSubscriptionType String type, Callback<List<CommerceSubscription>> callback) { - // TODO(crbug.com/1195469) Accept Profile instance from SubscriptionsManager. EndpointFetcher.fetchUsingOAuth( (response) -> { callback.onResult(createCommerceSubscriptions(response.getResponseString())); }, - Profile.getLastUsedRegularProfile(), OAUTH_NAME, + mProfile, OAUTH_NAME, CommerceSubscriptionsServiceConfig.SUBSCRIPTIONS_SERVICE_BASE_URL.getValue() + String.format(GET_SUBSCRIPTIONS_QUERY_PARAMS_TEMPLATE, type), GET_HTTPS_METHOD, CONTENT_TYPE, OAUTH_SCOPE, EMPTY_POST_DATA, @@ -81,14 +88,13 @@ } private void manageSubscriptions(JSONObject requestPayload, Callback<Boolean> callback) { - // TODO(crbug.com/1195469) Accept Profile instance from SubscriptionsManager. EndpointFetcher.fetchUsingOAuth( (response) -> { callback.onResult( didManageSubscriptionCallSucceed(response.getResponseString())); }, - Profile.getLastUsedRegularProfile(), OAUTH_NAME, + mProfile, OAUTH_NAME, CommerceSubscriptionsServiceConfig.SUBSCRIPTIONS_SERVICE_BASE_URL.getValue(), POST_HTTPS_METHOD, CONTENT_TYPE, OAUTH_SCOPE, requestPayload.toString(), HTTPS_REQUEST_TIMEOUT_MS);
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java index 60e99e37..cb8c470 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java
@@ -116,6 +116,11 @@ mNativeCommerceSubscriptionDB = nativePtr; } + @VisibleForTesting + public void setNativeCommerceSubscriptionDBForTesting(long nativeCommerceSubscriptionDB) { + mNativeCommerceSubscriptionDB = nativeCommerceSubscriptionDB; + } + /** * Generate the key for a {@link CommerceSubscription} used to store it in database. * @param subscription The {@link CommerceSubscription} whose key we want to generate.
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java index 29d3d1c..83d8389 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java
@@ -4,13 +4,15 @@ package org.chromium.chrome.browser.subscriptions; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; -import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; +import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManager; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.CommerceSubscriptionType; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.SubscriptionManagementType; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.TrackingIdType; @@ -44,6 +46,7 @@ private final PauseResumeWithNativeObserver mPauseResumeWithNativeObserver; private final SubscriptionsManagerImpl mSubscriptionManager; private final SharedPreferencesManager mSharedPreferencesManager; + private final PriceDropNotificationManager mPriceDropNotificationManager; public ImplicitPriceDropSubscriptionsManager(TabModelSelector tabModelSelector, ActivityLifecycleDispatcher activityLifecycleDispatcher, @@ -62,7 +65,6 @@ } }; mTabModelSelector.getModel(false).addObserver(mTabModelObserver); - DeferredStartupHandler.getInstance().addDeferredTask(this::initializeSubscriptions); mActivityLifecycleDispatcher = activityLifecycleDispatcher; mPauseResumeWithNativeObserver = new PauseResumeWithNativeObserver() { @Override @@ -75,6 +77,7 @@ }; mActivityLifecycleDispatcher.register(mPauseResumeWithNativeObserver); mSharedPreferencesManager = SharedPreferencesManager.getInstance(); + mPriceDropNotificationManager = new PriceDropNotificationManager(); } private boolean isUniqueTab(Tab tab) { @@ -108,17 +111,21 @@ } List<CommerceSubscription> subscriptions = new ArrayList<>(); for (Tab tab : urlTabMapping.values()) { + if (!hasOfferId(tab)) { + continue; + } CommerceSubscription subscription = new CommerceSubscription(CommerceSubscriptionType.PRICE_TRACK, ShoppingPersistedTabData.from(tab).getMainOfferId(), SubscriptionManagementType.CHROME_MANAGED, TrackingIdType.OFFER_ID); subscriptions.add(subscription); } - mSubscriptionManager.subscribe(subscriptions); + mSubscriptionManager.subscribe(subscriptions, + (didSucceed) -> { assert didSucceed : "Failed to create subscriptions."; }); } private void unsubscribe(Tab tab) { - if (!isUniqueTab(tab)) { + if (!isUniqueTab(tab) || !hasOfferId(tab)) { return; } @@ -126,11 +133,13 @@ new CommerceSubscription(CommerceSubscriptionType.PRICE_TRACK, ShoppingPersistedTabData.from(tab).getMainOfferId(), SubscriptionManagementType.CHROME_MANAGED, TrackingIdType.OFFER_ID); - mSubscriptionManager.unsubscribe(subscription); + mSubscriptionManager.unsubscribe(subscription, + (didSucceed) -> { assert didSucceed : "Failed to remove subscriptions."; }); } private boolean hasOfferId(Tab tab) { - return !ShoppingPersistedTabData.from(tab).getMainOfferId().isEmpty(); + return ShoppingPersistedTabData.from(tab) != null + && !TextUtils.isEmpty(ShoppingPersistedTabData.from(tab).getMainOfferId()); } // TODO(crbug.com/1186450): Extract this method to a utility class. Also, make the one-day time @@ -146,10 +155,11 @@ } private boolean shouldInitializeSubscriptions() { - if (System.currentTimeMillis() - - mSharedPreferencesManager.readLong( - CHROME_MANAGED_SUBSCRIPTIONS_TIMESTAMP, -1) - < CHROME_MANAGED_SUBSCRIPTIONS_TIME_THRESHOLD_MS) { + if ((!mPriceDropNotificationManager.canPostNotification()) + || (System.currentTimeMillis() + - mSharedPreferencesManager.readLong( + CHROME_MANAGED_SUBSCRIPTIONS_TIMESTAMP, -1) + < CHROME_MANAGED_SUBSCRIPTIONS_TIME_THRESHOLD_MS)) { return false; } mSharedPreferencesManager.writeLong(
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java index 5460ba3..de8b79bd 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java
@@ -15,25 +15,29 @@ /** * Creates a new subscription on the server if needed. * @param subscription The {@link CommerceSubscription} to add. + * @param callback indicates whether or not the operation was successful. */ - void subscribe(CommerceSubscription subscription); + void subscribe(CommerceSubscription subscription, Callback<Boolean> callback); /** * Creates new subscriptions in batch if needed. * @param subscriptions The list of {@link CommerceSubscription} to add. + * @param callback indicates whether or not the operation was successful. */ - void subscribe(List<CommerceSubscription> subscriptions); + void subscribe(List<CommerceSubscription> subscriptions, Callback<Boolean> callback); /** * Destroys a subscription on the server if needed. * @param subscription The {@link CommerceSubscription} to destroy. + * @param callback indicates whether or not the operation was successful. */ - void unsubscribe(CommerceSubscription subscription); + void unsubscribe(CommerceSubscription subscription, Callback<Boolean> callback); /** * Returns all subscriptions that match the provided type. * @param type The {@link CommerceSubscription.CommerceSubscriptionType} to query. * @param forceFetch Whether to fetch from server. + * @param callback returns the list of subscriptions. */ void getSubscriptions(@CommerceSubscription.CommerceSubscriptionType String type, boolean forceFetch, Callback<List<CommerceSubscription>> callback);
diff --git a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java index 7682d2e..d4928db 100644 --- a/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java +++ b/chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java
@@ -9,6 +9,7 @@ import org.chromium.base.Callback; import org.chromium.chrome.browser.profiles.Profile; +import java.util.ArrayList; import java.util.List; /** @@ -18,67 +19,76 @@ */ public class SubscriptionsManagerImpl implements SubscriptionsManager { private final CommerceSubscriptionsStorage mStorage; + private final CommerceSubscriptionsServiceProxy mServiceProxy; private static List<CommerceSubscription> sRemoteSubscriptionsForTesting; - public SubscriptionsManagerImpl() { - mStorage = new CommerceSubscriptionsStorage(Profile.getLastUsedRegularProfile()); + public SubscriptionsManagerImpl(Profile profile) { + mStorage = new CommerceSubscriptionsStorage(profile); + mServiceProxy = new CommerceSubscriptionsServiceProxy(profile); } /** * Creates a new subscription on the server-side and refreshes the local storage of * subscriptions. * @param subscription The {@link CommerceSubscription} to add. + * @param callback indicates whether or not the operation was successful. */ @Override - public void subscribe(CommerceSubscription subscription) { - String type = subscription.getType(); - if (type.equals(CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK)) { - // TODO(crbug.com/1186450): Replace getSubscriptions with callback from subscription - // request. - getSubscriptions(type, true, - remoteSubscriptions - -> updateStorageWithSubscriptions(type, remoteSubscriptions)); + public void subscribe(CommerceSubscription subscription, Callback<Boolean> callback) { + if (subscription == null || !isSubscriptionTypeSupported(subscription.getType())) { + callback.onResult(false); + return; } + + mServiceProxy.create(new ArrayList<CommerceSubscription>() { + { add(subscription); }; + }, (didSucceed) -> handleUpdateSubscriptionsResponse(didSucceed, subscription.getType())); } /** * Creates new subscriptions in batch if needed. * @param subscriptions The list of {@link CommerceSubscription} to add. + * @param callback indicates whether or not the operation was successful. */ @Override - public void subscribe(List<CommerceSubscription> subscriptions) { - if (subscriptions.size() == 0) return; + public void subscribe(List<CommerceSubscription> subscriptions, Callback<Boolean> callback) { + if (subscriptions.size() == 0) { + callback.onResult(false); + return; + } String type = subscriptions.get(0).getType(); - if (type.equals(CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK)) { - // TODO(crbug.com/1186450): Replace getSubscriptions with callback from subscription - // request. - getSubscriptions(type, true, - remoteSubscriptions - -> updateStorageWithSubscriptions(type, remoteSubscriptions)); + if (isSubscriptionTypeSupported(type)) { + mServiceProxy.create(subscriptions, + (didSucceed) -> handleUpdateSubscriptionsResponse(didSucceed, type)); + } else { + callback.onResult(false); } } /** * Destroys a subscription on the server-side and refreshes the local storage of subscriptions. * @param subscription The {@link CommerceSubscription} to destroy. + * @param callback indicates whether or not the operation was successful. */ @Override - public void unsubscribe(CommerceSubscription subscription) { + public void unsubscribe(CommerceSubscription subscription, Callback<Boolean> callback) { String type = subscription.getType(); - if (type.equals(CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK)) { - // TODO(crbug.com/1186450): Replace getSubscriptions with callback from unsubscription - // request. - getSubscriptions(type, true, - remoteSubscriptions - -> updateStorageWithSubscriptions(type, remoteSubscriptions)); + if (subscription == null || !isSubscriptionTypeSupported(type)) { + callback.onResult(false); + return; } + + mServiceProxy.delete(new ArrayList<CommerceSubscription>() { + { add(subscription); }; + }, (didSucceed) -> handleUpdateSubscriptionsResponse(didSucceed, type)); } /** * Returns all subscriptions that match the provided type. * @param type The {@link CommerceSubscription.CommerceSubscriptionType} to query. * @param forceFetch Whether to fetch from server. If no, fetch from local storage. + * @param callback returns the list of subscriptions. */ @Override public void getSubscriptions(@CommerceSubscription.CommerceSubscriptionType String type, @@ -87,12 +97,19 @@ callback.onResult(sRemoteSubscriptionsForTesting); return; } - if (!forceFetch) { + if (forceFetch) { + mServiceProxy.get(type, callback); + } else { mStorage.loadWithPrefix(String.valueOf(type), localSubscriptions -> callback.onResult(localSubscriptions)); } } + private boolean isSubscriptionTypeSupported( + @CommerceSubscription.CommerceSubscriptionType String type) { + return CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK.equals(type); + } + private void updateStorageWithSubscriptions( @CommerceSubscription.CommerceSubscriptionType String type, List<CommerceSubscription> remoteSubscriptions) { @@ -110,6 +127,16 @@ }); } + private void handleUpdateSubscriptionsResponse( + Boolean didSucceed, @CommerceSubscription.CommerceSubscriptionType String type) { + assert didSucceed : "Failed to handle update subscriptions response"; + if (didSucceed) { + getSubscriptions(type, true, + remoteSubscriptions + -> updateStorageWithSubscriptions(type, remoteSubscriptions)); + } + } + @VisibleForTesting public void setRemoteSubscriptionsForTesting(List<CommerceSubscription> subscriptions) { sRemoteSubscriptionsForTesting = subscriptions;
diff --git a/chrome/browser/commerce/subscriptions/android/java_sources.gni b/chrome/browser/commerce/subscriptions/android/java_sources.gni new file mode 100644 index 0000000..952a720 --- /dev/null +++ b/chrome/browser/commerce/subscriptions/android/java_sources.gni
@@ -0,0 +1,32 @@ +# Copyright 2021 The Chromium Authors.All rights reserved. +# Use of this source code is governed by a BSD - style license that can be +# found in the LICENSE file. + +# TODO(crbug/1210158): This should be a separate build target when circular +# dependencies are removed. +commerce_subscriptions_java_sources = [ + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscription.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionJsonSerializer.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsService.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceConfig.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactory.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxy.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorage.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManager.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManager.java", + "//chrome/browser/commerce/subscriptions/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImpl.java", +] + +commerce_subscriptions_java_deps = [ + "//base:base_java", + "//chrome/android:base_module_java", + "//chrome/browser/android/lifecycle:java", + "//chrome/browser/endpoint_fetcher:java", + "//chrome/browser/flags:java", + "//chrome/browser/preferences:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//url:gurl_java", +]
diff --git a/chrome/browser/commerce/subscriptions/test/android/BUILD.gn b/chrome/browser/commerce/subscriptions/test/android/BUILD.gn deleted file mode 100644 index c5e46e6..0000000 --- a/chrome/browser/commerce/subscriptions/test/android/BUILD.gn +++ /dev/null
@@ -1,67 +0,0 @@ -# Copyright 2021 The Chromium Authors.All rights reserved. -# Use of this source code is governed by a BSD - style license that can be -# found in the LICENSE file. - -import("//build/config/android/config.gni") -import("//build/config/android/rules.gni") - -java_library("junit") { - # Skip platform checks since Robolectric depends on requires_android targets. - bypass_platform_checks = true - - testonly = true - - sources = [ - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionJsonSerializerUnitTest.java", - "java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java", - ] - - deps = [ - "//base:base_java", - "//base:base_junit_test_support", - "//chrome/android:base_module_java", - "//chrome/android:chrome_java", - "//chrome/browser/android/lifecycle:java", - "//chrome/browser/commerce/subscriptions/android:java", - "//chrome/browser/flags:java", - "//chrome/browser/preferences:java", - "//chrome/browser/tab:java", - "//chrome/browser/tabmodel:java", - "//chrome/test/android:chrome_java_test_support", - "//third_party/android_deps:robolectric_all_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/androidx:androidx_test_runner_java", - "//third_party/hamcrest:hamcrest_core_java", - "//third_party/junit", - "//third_party/mockito:mockito_java", - "//url:gurl_java", - "//url:gurl_junit_test_support", - ] -} - -android_library("javatests") { - testonly = true - - sources = [ - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java", - "java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorageTest.java", - "java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsLoadCallbackHelper.java", - "java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java", - ] - - deps = [ - "//base:base_java", - "//base:base_java_test_support", - "//chrome/browser/commerce/subscriptions/android:java", - "//chrome/browser/endpoint_fetcher:java", - "//chrome/browser/flags:java", - "//chrome/browser/profiles/android:java", - "//chrome/test/android:chrome_java_test_support", - "//content/public/test/android:content_java_test_support", - "//third_party/androidx:androidx_test_core_java", - "//third_party/androidx:androidx_test_runner_java", - "//third_party/hamcrest:hamcrest_java", - "//third_party/junit", - "//third_party/mockito:mockito_java", - ] -}
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java new file mode 100644 index 0000000..8a9b1eb8 --- /dev/null +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java
@@ -0,0 +1,105 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.subscriptions; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; + +import androidx.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.profiles.ProfileManager; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.components.embedder_support.browser_context.BrowserContextHandle; + +/** + * Unit tests for {@link CommerceSubscriptionsServiceFactory}. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class CommerceSubscriptionsServiceFactoryUnitTest { + @Rule + public TestRule mProcessor = new Features.JUnitProcessor(); + + @Rule + public JniMocker mMocker = new JniMocker(); + + @Mock + private Profile mProfileOne; + + @Mock + private Profile mProfileTwo; + + @Mock + private CommerceSubscriptionsStorage.Natives mCommerceSubscriptionsStorageJni; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(false).when(mProfileOne).isOffTheRecord(); + doReturn(false).when(mProfileTwo).isOffTheRecord(); + mMocker.mock(CommerceSubscriptionsStorageJni.TEST_HOOKS, mCommerceSubscriptionsStorageJni); + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) { + CommerceSubscriptionsStorage storage = + (CommerceSubscriptionsStorage) invocation.getArguments()[0]; + storage.setNativeCommerceSubscriptionDBForTesting((long) 123); + return null; + } + }) + .when(mCommerceSubscriptionsStorageJni) + .init(any(CommerceSubscriptionsStorage.class), any(BrowserContextHandle.class)); + } + + @Test + @SmallTest + public void testFactoryMethod() { + CommerceSubscriptionsServiceFactory factory = new CommerceSubscriptionsServiceFactory(); + + Profile.setLastUsedProfileForTesting(mProfileOne); + CommerceSubscriptionsService regularProfileOneService = factory.getForLastUsedProfile(); + Assert.assertEquals(regularProfileOneService, factory.getForLastUsedProfile()); + + Profile.setLastUsedProfileForTesting(mProfileTwo); + CommerceSubscriptionsService regularProfileTwoService = factory.getForLastUsedProfile(); + Assert.assertNotEquals(regularProfileOneService, regularProfileTwoService); + Assert.assertEquals(regularProfileTwoService, factory.getForLastUsedProfile()); + + Profile.setLastUsedProfileForTesting(mProfileOne); + Assert.assertEquals(regularProfileOneService, factory.getForLastUsedProfile()); + + Profile.setLastUsedProfileForTesting(mProfileTwo); + Assert.assertEquals(regularProfileTwoService, factory.getForLastUsedProfile()); + } + + @Test + @SmallTest + public void testServiceDestroyedWhenProfileIsDestroyed() { + CommerceSubscriptionsServiceFactory factory = new CommerceSubscriptionsServiceFactory(); + Profile.setLastUsedProfileForTesting(mProfileOne); + CommerceSubscriptionsService service = factory.getForLastUsedProfile(); + Assert.assertEquals( + 1, CommerceSubscriptionsServiceFactory.sProfileToSubscriptionsService.size()); + ProfileManager.onProfileDestroyed(mProfileOne); + Assert.assertTrue( + CommerceSubscriptionsServiceFactory.sProfileToSubscriptionsService.isEmpty()); + } +}
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java index fa00f5f..dc2ac90 100644 --- a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java
@@ -92,7 +92,7 @@ mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock); doReturn(false).when(mProfile).isOffTheRecord(); Profile.setLastUsedProfileForTesting(mProfile); - mServiceProxy = new CommerceSubscriptionsServiceProxy(); + mServiceProxy = new CommerceSubscriptionsServiceProxy(mProfile); } @After
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java index bcb46d2..3bf9139 100644 --- a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java
@@ -15,6 +15,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.os.Build; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -27,12 +29,13 @@ import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; +import org.chromium.base.Callback; import org.chromium.base.UserDataHost; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; +import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManager; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.CommerceSubscriptionType; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.SubscriptionManagementType; import org.chromium.chrome.browser.subscriptions.CommerceSubscription.TrackingIdType; @@ -42,7 +45,10 @@ import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tasks.tab_management.PriceTrackingUtilities; +import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.components.browser_ui.notifications.MockNotificationManagerProxy; import org.chromium.url.GURL; import java.util.ArrayList; @@ -77,8 +83,6 @@ @Mock SubscriptionsManagerImpl mSubscriptionsManager; @Mock - DeferredStartupHandler mDeferredStartupHandler; - @Mock CriticalPersistedTabData mCriticalPersistedTabData1; @Mock CriticalPersistedTabData mCriticalPersistedTabData2; @@ -99,6 +103,8 @@ private CommerceSubscription mSubscription2; private ImplicitPriceDropSubscriptionsManager mImplicitSubscriptionsManager; private SharedPreferencesManager mSharedPreferencesManager; + private MockNotificationManagerProxy mMockNotificationManager; + private PriceDropNotificationManager mPriceDropNotificationManager; @Before public void setUp() { @@ -128,13 +134,21 @@ doNothing() .when(mActivityLifecycleDispatcher) .register(mPauseResumeWithNativeObserverCaptor.capture()); - DeferredStartupHandler.setInstanceForTests(mDeferredStartupHandler); mSharedPreferencesManager = SharedPreferencesManager.getInstance(); mSharedPreferencesManager.writeLong( ImplicitPriceDropSubscriptionsManager.CHROME_MANAGED_SUBSCRIPTIONS_TIMESTAMP, System.currentTimeMillis() - ImplicitPriceDropSubscriptionsManager .CHROME_MANAGED_SUBSCRIPTIONS_TIME_THRESHOLD_MS); + PriceTrackingUtilities.setIsSignedInAndSyncEnabledForTesting(true); + TabUiFeatureUtilities.ENABLE_PRICE_NOTIFICATION.setForTesting(true); + mMockNotificationManager = new MockNotificationManagerProxy(); + mMockNotificationManager.setNotificationsEnabled(true); + PriceDropNotificationManager.setNotificationManagerForTesting(mMockNotificationManager); + mPriceDropNotificationManager = new PriceDropNotificationManager(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mPriceDropNotificationManager.createNotificationChannel(); + } mImplicitSubscriptionsManager = new ImplicitPriceDropSubscriptionsManager( mTabModelSelector, mActivityLifecycleDispatcher, mSubscriptionsManager); @@ -142,13 +156,15 @@ @After public void tearDown() { - DeferredStartupHandler.setInstanceForTests(null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mPriceDropNotificationManager.deleteChannelForTesting(); + } + PriceDropNotificationManager.setNotificationManagerForTesting(null); } @Test public void testInitialSetup() { verify(mTabModel).addObserver(any(TabModelObserver.class)); - verify(mDeferredStartupHandler).addDeferredTask(any(Runnable.class)); verify(mActivityLifecycleDispatcher).register(any(PauseResumeWithNativeObserver.class)); } @@ -159,7 +175,18 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); verify(mSubscriptionsManager) - .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription1, mSubscription2)))); + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription1, mSubscription2))), + any(Callback.class)); + } + + @Test + public void testInitialSubscription_FeatureDisabled() { + doReturn(2).when(mTabModel).getCount(); + + TabUiFeatureUtilities.ENABLE_PRICE_NOTIFICATION.setForTesting(false); + mImplicitSubscriptionsManager.initializeSubscriptions(); + + verify(mSubscriptionsManager, times(0)).subscribe(any(List.class), any(Callback.class)); } @Test @@ -171,7 +198,8 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); - verify(mSubscriptionsManager).subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2)))); + verify(mSubscriptionsManager) + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2))), any(Callback.class)); } @Test @@ -180,7 +208,8 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); - verify(mSubscriptionsManager).subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2)))); + verify(mSubscriptionsManager) + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2))), any(Callback.class)); } @Test @@ -194,7 +223,8 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); - verify(mSubscriptionsManager).subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2)))); + verify(mSubscriptionsManager) + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2))), any(Callback.class)); } @Test @@ -203,7 +233,8 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); - verify(mSubscriptionsManager).subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2)))); + verify(mSubscriptionsManager) + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription2))), any(Callback.class)); } @Test @@ -214,7 +245,7 @@ mImplicitSubscriptionsManager.initializeSubscriptions(); - verify(mSubscriptionsManager, times(0)).subscribe(any(List.class)); + verify(mSubscriptionsManager, times(0)).subscribe(any(List.class), any(Callback.class)); } @Test @@ -222,14 +253,16 @@ mPauseResumeWithNativeObserverCaptor.getValue().onResumeWithNative(); verify(mSubscriptionsManager) - .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription1, mSubscription2)))); + .subscribe(eq(new ArrayList<>(Arrays.asList(mSubscription1, mSubscription2))), + any(Callback.class)); } @Test public void testTabClosure() { mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - verify(mSubscriptionsManager, times(1)).unsubscribe(mSubscriptionCaptor.capture()); + verify(mSubscriptionsManager, times(1)) + .unsubscribe(mSubscriptionCaptor.capture(), any(Callback.class)); assertThat(mSubscriptionCaptor.getAllValues().get(0).getTrackingId(), equalTo(String.valueOf(OFFER1_ID))); } @@ -238,7 +271,8 @@ public void testTabRemove() { mTabModelObserverCaptor.getValue().tabRemoved(mTab1); - verify(mSubscriptionsManager, times(1)).unsubscribe(mSubscriptionCaptor.capture()); + verify(mSubscriptionsManager, times(1)) + .unsubscribe(mSubscriptionCaptor.capture(), any(Callback.class)); assertThat(mSubscriptionCaptor.getAllValues().get(0).getTrackingId(), equalTo(String.valueOf(OFFER1_ID))); } @@ -252,7 +286,8 @@ mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - verify(mSubscriptionsManager, never()).unsubscribe(mSubscriptionCaptor.capture()); + verify(mSubscriptionsManager, never()) + .unsubscribe(mSubscriptionCaptor.capture(), any(Callback.class)); } @Test
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java index 05a2c66..791268a 100644 --- a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java
@@ -16,12 +16,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -50,6 +52,15 @@ public BlankCTATabInitialStateRule mBlankCTATabInitialStateRule = new BlankCTATabInitialStateRule(sActivityTestRule, false); + @Mock + private Profile mProfile; + + @Rule + public JniMocker mMocker = new JniMocker(); + + @Mock + private CommerceSubscriptionsStorage.Natives mCommerceSubscriptionsStorageJni; + private static final String OFFER_ID_1 = "offer_id_1"; private static final String OFFER_ID_2 = "offer_id_2"; private static final String OFFER_ID_3 = "offer_id_3"; @@ -64,9 +75,10 @@ @Before public void setUp() throws Exception { + mMocker.mock(CommerceSubscriptionsStorageJni.TEST_HOOKS, mCommerceSubscriptionsStorageJni); TestThreadUtils.runOnUiThreadBlocking(() -> { - mStorage = new CommerceSubscriptionsStorage(Profile.getLastUsedRegularProfile()); - mSubscriptionsManager = new SubscriptionsManagerImpl(); + mStorage = new CommerceSubscriptionsStorage(mProfile); + mSubscriptionsManager = new SubscriptionsManagerImpl(mProfile); }); mSubscription1 = @@ -115,8 +127,11 @@ CommerceSubscriptionsStorage.getKey(subscription), subscription); } mSubscriptionsManager.setRemoteSubscriptionsForTesting(remoteSubscriptions); + // Test local cache is updated after single subscription. - ThreadUtils.runOnUiThreadBlocking(() -> mSubscriptionsManager.subscribe(newSubscription)); + ThreadUtils.runOnUiThreadBlocking( + () -> mSubscriptionsManager.subscribe(newSubscription, (didSucceed) -> {})); + loadSingleAndCheckResult(CommerceSubscriptionsStorage.getKey(mSubscription3), null); loadPrefixAndCheckResult( CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK, expectedSubscriptions); @@ -143,7 +158,8 @@ } mSubscriptionsManager.setRemoteSubscriptionsForTesting(remoteSubscriptions); // Test local cache is updated after subscribing a list of subscriptions. - ThreadUtils.runOnUiThreadBlocking(() -> mSubscriptionsManager.subscribe(newSubscriptions)); + ThreadUtils.runOnUiThreadBlocking( + () -> mSubscriptionsManager.subscribe(newSubscriptions, (didSucceed) -> {})); loadSingleAndCheckResult(CommerceSubscriptionsStorage.getKey(mSubscription3), null); loadPrefixAndCheckResult( CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK, expectedSubscriptions); @@ -170,7 +186,7 @@ mSubscriptionsManager.setRemoteSubscriptionsForTesting(remoteSubscriptions); // Test local cache is updated after unsubscription. ThreadUtils.runOnUiThreadBlocking( - () -> mSubscriptionsManager.unsubscribe(removedSubscription)); + () -> mSubscriptionsManager.unsubscribe(removedSubscription, (didSucceed) -> {})); loadSingleAndCheckResult(CommerceSubscriptionsStorage.getKey(removedSubscription), null); loadPrefixAndCheckResult( CommerceSubscription.CommerceSubscriptionType.PRICE_TRACK, expectedSubscriptions);
diff --git a/chrome/browser/commerce/subscriptions/test/android/test_java_sources.gni b/chrome/browser/commerce/subscriptions/test/android/test_java_sources.gni new file mode 100644 index 0000000..a0598b979 --- /dev/null +++ b/chrome/browser/commerce/subscriptions/test/android/test_java_sources.gni
@@ -0,0 +1,60 @@ +# Copyright 2021 The Chromium Authors.All rights reserved. +# Use of this source code is governed by a BSD - style license that can be +# found in the LICENSE file. + +# TODO(crbug/1210158): This should be a separate build target when circular +# dependencies are removed. +commerce_subscriptions_junit_test_sources = [ + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionJsonSerializerUnitTest.java", + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java", + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/ImplicitPriceDropSubscriptionsManagerUnitTest.java", +] + +commerce_subscriptions_junit_test_deps = [ + "//base:base_java", + "//base:base_java_test_support", + "//base:base_junit_test_support", + "//chrome/android:base_module_java", + "//chrome/browser/android/lifecycle:java", + "//chrome/browser/flags:java", + "//chrome/browser/preferences:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", + "//chrome/test/android:chrome_java_test_support", + "//components/browser_ui/notifications/android:test_support_java", + "//components/embedder_support/android:browser_context_java", + "//third_party/android_deps:robolectric_all_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/hamcrest:hamcrest_core_java", + "//third_party/junit", + "//third_party/mockito:mockito_java", + "//url:gurl_java", + "//url:gurl_junit_test_support", +] + +commerce_subscriptions_java_test_sources = [ + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceProxyUnitTest.java", + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsStorageTest.java", + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsLoadCallbackHelper.java", + "//chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/SubscriptionsManagerImplTest.java", +] + +commerce_subscriptions_java_test_deps = [ + "//base:base_java", + "//base:base_java_test_support", + "//chrome/android:base_module_java", + "//chrome/browser/android/lifecycle:java", + "//chrome/browser/endpoint_fetcher:java", + "//chrome/browser/flags:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/tabmodel:java", + "//chrome/test/android:chrome_java_test_support", + "//content/public/test/android:content_java_test_support", + "//third_party/androidx:androidx_test_core_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/hamcrest:hamcrest_java", + "//third_party/junit", + "//third_party/mockito:mockito_java", +]
diff --git a/chrome/browser/download/android/BUILD.gn b/chrome/browser/download/android/BUILD.gn index 8b95deed..373c3a1 100644 --- a/chrome/browser/download/android/BUILD.gn +++ b/chrome/browser/download/android/BUILD.gn
@@ -74,6 +74,7 @@ "//chrome/browser/offline_pages/android:java", "//chrome/browser/preferences:java", "//chrome/browser/profiles/android:java", + "//chrome/browser/settings:java", "//chrome/browser/ui/messages/android:java", "//chrome/browser/util:java", "//components/browser_ui/modaldialog/android:java",
diff --git a/chrome/browser/download/android/download_dialog_bridge.cc b/chrome/browser/download/android/download_dialog_bridge.cc index 5d2e2543f..6ee74b29 100644 --- a/chrome/browser/download/android/download_dialog_bridge.cc +++ b/chrome/browser/download/android/download_dialog_bridge.cc
@@ -177,6 +177,13 @@ return DownloadDialogBridge::ShouldShowDateTimePicker(); } +jboolean JNI_DownloadDialogBridge_IsLocationDialogManaged(JNIEnv* env) { + PrefService* pref_service = + ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs(); + + return pref_service->IsManagedPreference(prefs::kPromptForDownload); +} + // static long DownloadDialogBridge::GetDownloadLaterMinFileSize() { return base::GetFieldTrialParamByFeatureAsInt(
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadDialogBridge.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadDialogBridge.java index 8117ae3f..a95c7a8 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadDialogBridge.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadDialogBridge.java
@@ -329,6 +329,21 @@ getPrefService().setInteger(Pref.PROMPT_FOR_DOWNLOAD_ANDROID, status); } + /** + * @return The value for {@link Pref#PROMPT_FOR_DOWNLOAD}. This is currently only used by + * enterprise policy. + */ + public static boolean getPromptForDownloadPolicy() { + return getPrefService().getBoolean(Pref.PROMPT_FOR_DOWNLOAD); + } + + /** + * @return whether to prompt the download location dialog is controlled by enterprise policy. + */ + public static boolean isLocationDialogManaged() { + return DownloadDialogBridgeJni.get().isLocationDialogManaged(); + } + public static boolean shouldShowDateTimePicker() { return DownloadDialogBridgeJni.get().shouldShowDateTimePicker(); } @@ -347,5 +362,6 @@ boolean isDataReductionProxyEnabled(); long getDownloadLaterMinFileSize(); boolean shouldShowDateTimePicker(); + boolean isLocationDialogManaged(); } }
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadDialogUtils.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadDialogUtils.java index 4265876..30044009 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadDialogUtils.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadDialogUtils.java
@@ -32,6 +32,7 @@ /** * Returns whether the download location suggestion dialog should be prompted. * @param dirs The available directories. + * @param defaultLocation The default download location. * @param totalBytes The download size. */ public static boolean shouldSuggestDownloadLocation(
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java index 859f8fa..88a62c66 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLocationDialogCoordinator.java
@@ -46,6 +46,7 @@ private @DownloadLocationDialogType int mDialogType; private String mSuggestedPath; private Context mContext; + private boolean mLocationDialogManaged; /** * Initializes the download location dialog. @@ -75,6 +76,7 @@ mTotalBytes = totalBytes; mDialogType = dialogType; mSuggestedPath = suggestedPath; + mLocationDialogManaged = DownloadDialogBridge.isLocationDialogManaged(); DownloadDirectoryProvider.getInstance().getAllDirectoriesOptions( (ArrayList<DirectoryOption> dirs) -> { onDirectoryOptionsRetrieved(dirs); }); @@ -129,7 +131,8 @@ // If there is only one directory available, don't show the default dialog, and set the // download directory to default. Dialog will still show for other types of dialogs, like // name conflict or disk error. - if (dirs.size() == 1 && mDialogType == DownloadLocationDialogType.DEFAULT) { + if (dirs.size() == 1 && !mLocationDialogManaged + && mDialogType == DownloadLocationDialogType.DEFAULT) { final DirectoryOption dir = dirs.get(0); if (dir.type == DirectoryOption.DownloadLocationDirectoryType.DEFAULT) { assert (!TextUtils.isEmpty(dir.location)); @@ -175,7 +178,8 @@ builder.with( DownloadLocationDialogProperties.FILE_NAME, new File(mSuggestedPath).getName()); builder.with(DownloadLocationDialogProperties.SHOW_SUBTITLE, true); - builder.with(DownloadLocationDialogProperties.DONT_SHOW_AGAIN_CHECKBOX_SHOWN, true); + builder.with(DownloadLocationDialogProperties.DONT_SHOW_AGAIN_CHECKBOX_SHOWN, + !mLocationDialogManaged); switch (mDialogType) { case DownloadLocationDialogType.LOCATION_FULL: @@ -203,8 +207,8 @@ mContext.getString(R.string.download_location_name_too_long)); break; case DownloadLocationDialogType.LOCATION_SUGGESTION: - builder.with(DownloadLocationDialogProperties.TITLE, - mContext.getString(R.string.download_location_dialog_title)); + assert !mLocationDialogManaged; + builder.with(DownloadLocationDialogProperties.TITLE, getDefaultTitle()); builder.with(DownloadLocationDialogProperties.SHOW_LOCATION_AVAILABLE_SPACE, true); assert mTotalBytes > 0; builder.with(DownloadLocationDialogProperties.FILE_SIZE, @@ -212,8 +216,8 @@ builder.with(DownloadLocationDialogProperties.SHOW_SUBTITLE, false); break; case DownloadLocationDialogType.DEFAULT: - builder.with(DownloadLocationDialogProperties.TITLE, - mContext.getString(R.string.download_location_dialog_title)); + builder.with(DownloadLocationDialogProperties.TITLE, getDefaultTitle()); + if (mTotalBytes > 0) { builder.with(DownloadLocationDialogProperties.SUBTITLE, DownloadUtils.getStringForBytes(mContext, mTotalBytes)); @@ -226,6 +230,12 @@ return builder.build(); } + private String getDefaultTitle() { + return mContext.getString(mLocationDialogManaged + ? R.string.download_location_dialog_title_confirm_download + : R.string.download_location_dialog_title); + } + /** * Pass along information from location dialog to native. * @@ -254,10 +264,10 @@ // Update preference to show prompt based on whether checkbox is checked only when the user // click the positive button. - if (dontShowAgain) { - DownloadDialogBridge.setPromptForDownloadAndroid(DownloadPromptStatus.DONT_SHOW); - } else { - DownloadDialogBridge.setPromptForDownloadAndroid(DownloadPromptStatus.SHOW_PREFERENCE); + if (!mLocationDialogManaged) { + DownloadDialogBridge.setPromptForDownloadAndroid(dontShowAgain + ? DownloadPromptStatus.DONT_SHOW + : DownloadPromptStatus.SHOW_PREFERENCE); } }
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java index afca352..3396b841 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/settings/DownloadSettings.java
@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileKey; +import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate; import org.chromium.components.browser_ui.settings.ChromeSwitchPreference; import org.chromium.components.browser_ui.settings.SettingsUtils; import org.chromium.components.prefs.PrefService; @@ -27,6 +28,7 @@ /** * Fragment containing Download settings. */ +// TODO(xingliu): Add a test for this. public class DownloadSettings extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener { static final String PREF_LOCATION_CHANGE = "location_change"; @@ -50,7 +52,8 @@ (ChromeSwitchPreference) findPreference(PREF_DOWNLOAD_LATER_PROMPT_ENABLED); mDownloadLaterPromptEnabledPref.setOnPreferenceChangeListener(this); - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_LATER)) { + boolean locationManaged = DownloadDialogBridge.isLocationDialogManaged(); + if (locationManaged || !ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_LATER)) { getPreferenceScreen().removePreference( findPreference(PREF_DOWNLOAD_LATER_PROMPT_ENABLED)); } @@ -58,6 +61,13 @@ mLocationPromptEnabledPref = (ChromeSwitchPreference) findPreference(PREF_LOCATION_PROMPT_ENABLED); mLocationPromptEnabledPref.setOnPreferenceChangeListener(this); + mLocationPromptEnabledPref.setManagedPreferenceDelegate( + new ChromeManagedPreferenceDelegate() { + @Override + public boolean isPreferenceControlledByPolicy(Preference preference) { + return DownloadDialogBridge.isLocationDialogManaged(); + } + }); mLocationChangePref = (DownloadLocationPreference) findPreference(PREF_LOCATION_CHANGE); if (PrefetchConfiguration.isPrefetchingFlagEnabled()) { @@ -100,10 +110,17 @@ !(downloadLaterPromptStatus == DownloadLaterPromptStatus.DONT_SHOW)); } - // Location prompt is marked enabled if the prompt status is not DONT_SHOW. - boolean isLocationPromptEnabled = DownloadDialogBridge.getPromptForDownloadAndroid() - != DownloadPromptStatus.DONT_SHOW; - mLocationPromptEnabledPref.setChecked(isLocationPromptEnabled); + if (DownloadDialogBridge.isLocationDialogManaged()) { + // Location prompt can be controlled by the enterprise policy. + mLocationPromptEnabledPref.setChecked( + DownloadDialogBridge.getPromptForDownloadPolicy()); + } else { + // Location prompt is marked enabled if the prompt status is not DONT_SHOW. + boolean isLocationPromptEnabled = DownloadDialogBridge.getPromptForDownloadAndroid() + != DownloadPromptStatus.DONT_SHOW; + mLocationPromptEnabledPref.setChecked(isLocationPromptEnabled); + mLocationPromptEnabledPref.setEnabled(true); + } if (mPrefetchingEnabled != null) { mPrefetchingEnabled.setChecked(PrefetchConfiguration.isPrefetchingEnabledInSettings(
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc index 72eb2b0..f5ce4b6 100644 --- a/chrome/browser/download/download_prefs.cc +++ b/chrome/browser/download/download_prefs.cc
@@ -395,6 +395,10 @@ // Return the Android prompt for download only. #if defined(OS_ANDROID) + // Use |prompt_for_download_| preference for enterprise policy. + if (prompt_for_download_.IsManaged()) + return prompt_for_download_.GetValue(); + // As long as they haven't indicated in preferences they do not want the // dialog shown, show the dialog. return *prompt_for_download_android_ != @@ -406,6 +410,9 @@ bool DownloadPrefs::PromptDownloadLater() const { #ifdef OS_ANDROID + if (prompt_for_download_.IsManaged()) + return false; + if (base::FeatureList::IsEnabled(download::features::kDownloadLater)) { return *prompt_for_download_later_ != static_cast<int>(DownloadLaterPromptStatus::kDontShow);
diff --git a/chrome/browser/download/download_prefs_unittest.cc b/chrome/browser/download/download_prefs_unittest.cc index b53026a9..afb61dc0 100644 --- a/chrome/browser/download/download_prefs_unittest.cc +++ b/chrome/browser/download/download_prefs_unittest.cc
@@ -496,6 +496,33 @@ EXPECT_TRUE(prefs.HasDownloadLaterPromptShown()); } +// Verfies the returned value of PromptForDownload() and PromptDownloadLater() +// when prefs::kPromptForDownload is managed by enterprise policy, +TEST(DownloadPrefsTest, ManagedPromptForDownload) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(download::features::kDownloadLater); + + content::BrowserTaskEnvironment task_environment_; + TestingProfile profile; + profile.GetTestingPrefService()->SetManagedPref( + prefs::kPromptForDownload, std::make_unique<base::Value>(true)); + DownloadPrefs prefs(&profile); + + profile.GetPrefs()->SetInteger( + prefs::kDownloadLaterPromptStatus, + static_cast<int>(DownloadLaterPromptStatus::kShowPreference)); + profile.GetPrefs()->SetInteger( + prefs::kPromptForDownloadAndroid, + static_cast<int>(DownloadPromptStatus::DONT_SHOW)); + EXPECT_FALSE(prefs.PromptDownloadLater()); + EXPECT_TRUE(prefs.PromptForDownload()); + + profile.GetTestingPrefService()->SetManagedPref( + prefs::kPromptForDownload, std::make_unique<base::Value>(false)); + EXPECT_FALSE(prefs.PromptDownloadLater()); + EXPECT_FALSE(prefs.PromptForDownload()); +} + #endif // OS_ANDROID } // namespace
diff --git a/chrome/browser/enterprise/connectors/device_trust/BUILD.gn b/chrome/browser/enterprise/connectors/device_trust/BUILD.gn index 12c5e4a..d7849d7a 100644 --- a/chrome/browser/enterprise/connectors/device_trust/BUILD.gn +++ b/chrome/browser/enterprise/connectors/device_trust/BUILD.gn
@@ -8,7 +8,7 @@ proto_in_dir = "//chrome/browser/enterprise/connectors/device_trust/attestation_protos" proto_out_dir = "chrome/browser/enterprise/connectors/device_trust/" - sources = [ "${proto_in_dir}/keystore.proto" ] + sources = [ "${proto_in_dir}/device_trust_keystore.proto" ] generate_python = false } @@ -16,7 +16,7 @@ proto_in_dir = "//chrome/browser/enterprise/connectors/device_trust/attestation_protos" proto_out_dir = "chrome/browser/enterprise/connectors/device_trust/" - sources = [ "${proto_in_dir}/attestation_ca.proto" ] + sources = [ "${proto_in_dir}/device_trust_attestation_ca.proto" ] generate_python = false } @@ -24,7 +24,7 @@ proto_in_dir = "//chrome/browser/enterprise/connectors/device_trust/attestation_protos" proto_out_dir = "chrome/browser/enterprise/connectors/device_trust/" - sources = [ "${proto_in_dir}/interface.proto" ] + sources = [ "${proto_in_dir}/device_trust_interface.proto" ] deps = [ ":attestation_ca_proto", ":keystore_proto", @@ -36,6 +36,6 @@ proto_in_dir = "//chrome/browser/enterprise/connectors/device_trust/attestation_protos" proto_out_dir = "chrome/browser/enterprise/connectors/device_trust/" - sources = [ "${proto_in_dir}/google_key.proto" ] + sources = [ "${proto_in_dir}/device_trust_google_key.proto" ] generate_python = false }
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/attestation_ca.proto b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_attestation_ca.proto similarity index 99% rename from chrome/browser/enterprise/connectors/device_trust/attestation_protos/attestation_ca.proto rename to chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_attestation_ca.proto index e3fac270..bcf7478 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/attestation_ca.proto +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_attestation_ca.proto
@@ -10,7 +10,7 @@ option optimize_for = LITE_RUNTIME; -package attestation; +package enterprise_connectors; // Enumerates various certificate profiles supported by the Attestation CA. enum CertificateProfile {
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/google_key.proto b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_google_key.proto similarity index 96% rename from chrome/browser/enterprise/connectors/device_trust/attestation_protos/google_key.proto rename to chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_google_key.proto index 8fd316e..2b2f04e 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/google_key.proto +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_google_key.proto
@@ -10,7 +10,7 @@ option optimize_for = LITE_RUNTIME; -package attestation; +package enterprise_connectors; // The RSA public key of Google key used by attestation service. Only used // internally for attestation service, this message is specialized to contain a
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/interface.proto b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_interface.proto similarity index 99% rename from chrome/browser/enterprise/connectors/device_trust/attestation_protos/interface.proto rename to chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_interface.proto index 2209dae..fed1ba20 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/interface.proto +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_interface.proto
@@ -10,10 +10,10 @@ option optimize_for = LITE_RUNTIME; -import "attestation_ca.proto"; -import "keystore.proto"; +import "device_trust_attestation_ca.proto"; +import "device_trust_keystore.proto"; -package attestation; +package enterprise_connectors; enum AttestationStatus { STATUS_SUCCESS = 0;
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/keystore.proto b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_keystore.proto similarity index 94% rename from chrome/browser/enterprise/connectors/device_trust/attestation_protos/keystore.proto rename to chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_keystore.proto index b51c08b5..966a870 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_protos/keystore.proto +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_protos/device_trust_keystore.proto
@@ -10,7 +10,7 @@ option optimize_for = LITE_RUNTIME; -package attestation; +package enterprise_connectors; // Describes key type. enum KeyType {
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_service.cc b/chrome/browser/enterprise/connectors/device_trust/attestation_service.cc index c852b57..d668ff5 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_service.cc +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_service.cc
@@ -5,14 +5,17 @@ #include "chrome/browser/enterprise/connectors/device_trust/attestation_service.h" #include "base/base64.h" +#include "base/bind.h" #include "base/json/json_reader.h" -#include "base/json/json_string_value_serializer.h" #include "base/json/json_writer.h" #include "base/logging.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "base/values.h" +#include "chrome/browser/enterprise/connectors/device_trust/crypto_utility.h" #include "chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h" -namespace attestation { +namespace enterprise_connectors { AttestationService::AttestationService() { #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) @@ -23,9 +26,20 @@ AttestationService::~AttestationService() = default; +bool AttestationService::ChallengeComesFromVerifiedAccess( + const std::string& serialized_signed_data, + const std::string& public_key_modulus_hex) { + SignedData signed_challenge; + signed_challenge.ParseFromString(serialized_signed_data); + // Verify challenge signature. + return enterprise_connector::CryptoUtility::VerifySignatureUsingHexKey( + public_key_modulus_hex, signed_challenge.data(), + signed_challenge.signature()); +} + std::string AttestationService::JsonChallengeToProtobufChallenge( const std::string& challenge) { - attestation::SignedData signed_challenge; + SignedData signed_challenge; // Get challenge and decode it. absl::optional<base::Value> data = base::JSONReader::Read( challenge, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS); @@ -137,4 +151,55 @@ return true; } -} // namespace attestation +void AttestationService::BuildChallengeResponseForVAChallenge( + const std::string& challenge, + AttestationCallback callback) { + std::string serialized_signed_data = + JsonChallengeToProtobufChallenge(challenge); + + AttestationCallback reply = base::BindOnce( + &AttestationService::PaserChallengeResponseAndRunCallback, + weak_factory_.GetWeakPtr(), challenge, std::move(callback)); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::BindOnce( + &AttestationService::VerifyChallengeAndMaybeCreateChallengeResponse, + base::Unretained(this), JsonChallengeToProtobufChallenge(challenge), + google_keys_.va_signing_key(VAType::DEFAULT_VA).modulus_in_hex()), + std::move(reply)); +} + +std::string AttestationService::VerifyChallengeAndMaybeCreateChallengeResponse( + const std::string& serialized_signed_data, + const std::string& public_key_modulus_hex) { + if (!ChallengeComesFromVerifiedAccess(serialized_signed_data, + public_key_modulus_hex)) { + LOG(ERROR) << "Challenge signature verification did not succeed."; + return std::string(); + } + // If the verification that the challenge comes from Verified Access succeed, + // generate the challenge response. + SignEnterpriseChallengeRequest request; + SignEnterpriseChallengeReply result; + request.set_challenge(serialized_signed_data); + SignEnterpriseChallenge(request, &result); + return result.challenge_response(); +} + +void AttestationService::PaserChallengeResponseAndRunCallback( + const std::string& challenge, + AttestationCallback callback, + const std::string& challenge_response_proto) { + if (challenge_response_proto != std::string()) { + // Return to callback (throttle with the challenge response) with empty + // challenge response. + std::move(callback).Run( + ProtobufChallengeToJsonChallenge(challenge_response_proto)); + } else { + // Make challenge response + std::move(callback).Run(""); + } +} + +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_service.h b/chrome/browser/enterprise/connectors/device_trust/attestation_service.h index 206a5b9..5183d08 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_service.h +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_service.h
@@ -5,18 +5,16 @@ #ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_ATTESTATION_SERVICE_H_ #define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_ATTESTATION_SERVICE_H_ +#include "base/bind.h" #include "build/build_config.h" -#include "chrome/browser/enterprise/connectors/device_trust/attestation_ca.pb.h" -#include "chrome/browser/enterprise/connectors/device_trust/interface.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_attestation_ca.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_interface.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/google_keys.h" namespace enterprise_connectors { class DeviceTrustKeyPair; -} - -namespace attestation { - // This class is in charge of handling the key pair used for attestation. Also // provides the methods needed in the handshake between Chrome, an IdP and // Verified Access. @@ -25,6 +23,8 @@ // `SignEnterpriseChallengeReply`. class AttestationService { public: + using AttestationCallback = base::OnceCallback<void(const std::string&)>; + AttestationService(); ~AttestationService(); @@ -64,6 +64,21 @@ std::string ProtobufChallengeToJsonChallenge( const std::string& challenge_response); + // Verify challenge comes from Verify Access. + bool ChallengeComesFromVerifiedAccess( + const std::string& serialized_signed_data, + const std::string& public_key_modulus_hex); + + // Returns the challenge response proto. + std::string VerifyChallengeAndMaybeCreateChallengeResponse( + const std::string& serialized_signed_data, + const std::string& public_key_modulus_hex); + + // If the challenge comes from Verified Access, generate the + // proper challenge response, otherwise reply with empty string. + void BuildChallengeResponseForVAChallenge(const std::string& challenge, + AttestationCallback callback); + private: // Sign the challenge and return the challenge response in // `result.challenge_response`. @@ -74,11 +89,19 @@ // Sign `data` using `key_pair_` and store that value in `signature`. bool SignChallengeData(const std::string& data, std::string* response); + void PaserChallengeResponseAndRunCallback( + const std::string& challenge, + AttestationCallback callback, + const std::string& challenge_response_proto); + #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) std::unique_ptr<enterprise_connectors::DeviceTrustKeyPair> key_pair_; #endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) + + GoogleKeys google_keys_; + base::WeakPtrFactory<AttestationService> weak_factory_{this}; }; -} // namespace attestation +} // namespace enterprise_connectors #endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_ATTESTATION_SERVICE_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation_service_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/attestation_service_unittest.cc index 2ec5e3b4..ccd06e1 100644 --- a/chrome/browser/enterprise/connectors/device_trust/attestation_service_unittest.cc +++ b/chrome/browser/enterprise/connectors/device_trust/attestation_service_unittest.cc
@@ -6,7 +6,6 @@ #include "base/base64.h" #include "base/json/json_reader.h" -#include "base/logging.h" #include "base/values.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" @@ -34,7 +33,7 @@ } // namespace -namespace attestation { +namespace enterprise_connectors { class AttestationServiceTest : public testing::Test { public: @@ -84,4 +83,4 @@ std::string()); } -} // namespace attestation +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/crypto_utility.cc b/chrome/browser/enterprise/connectors/device_trust/crypto_utility.cc new file mode 100644 index 0000000..bd56f4a --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/crypto_utility.cc
@@ -0,0 +1,81 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/device_trust/crypto_utility.h" + +#include "base/containers/span.h" +#include "base/logging.h" +#include "crypto/signature_verifier.h" +#include "third_party/boringssl/src/include/openssl/bn.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/mem.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" + +namespace enterprise_connector { + +namespace { + +const unsigned int kWellKnownExponent = 65537; + +bool CreatePublicKeyFromHex(const std::string& public_key_modulus_hex, + std::vector<uint8_t>& public_key_info) { + bssl::UniquePtr<RSA> rsa(RSA_new()); + bssl::UniquePtr<BIGNUM> n(BN_new()); + bssl::UniquePtr<BIGNUM> e(BN_new()); + if (!rsa || !e || !n) { + LOG(ERROR) << __func__ << ": Failed to allocate RSA or BIGNUMs."; + return false; + } + BIGNUM* pn = n.get(); + if (!BN_set_word(e.get(), kWellKnownExponent) || + !BN_hex2bn(&pn, public_key_modulus_hex.c_str())) { + LOG(ERROR) << __func__ << ": Failed to generate exponent or modulus."; + return false; + } + if (!RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr)) { + LOG(ERROR) << __func__ << ": Failed to set exponent or modulus."; + return false; + } + + bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new()); + EVP_PKEY_assign_RSA(public_key.get(), rsa.release()); + + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_public_key(cbb.get(), public_key.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + public_key_info.assign(der, der + der_len); + OPENSSL_free(der); + + return true; +} + +} // namespace + +// static +bool CryptoUtility::VerifySignatureUsingHexKey( + const std::string& public_key_modulus_hex, + const std::string& data, + const std::string& signature) { + std::vector<uint8_t> public_key_info; + if (!CreatePublicKeyFromHex(public_key_modulus_hex, public_key_info)) { + return false; + } + + crypto::SignatureVerifier verifier; + if (!verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA256, + base::as_bytes(base::make_span(signature)), + base::as_bytes(base::make_span(public_key_info)))) + return false; + + verifier.VerifyUpdate(base::as_bytes(base::make_span(data))); + return verifier.VerifyFinal(); +} + +} // namespace enterprise_connector
diff --git a/chrome/browser/enterprise/connectors/device_trust/crypto_utility.h b/chrome/browser/enterprise/connectors/device_trust/crypto_utility.h new file mode 100644 index 0000000..6507184fa --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/crypto_utility.h
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_CRYPTO_UTILITY_H_ +#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_CRYPTO_UTILITY_H_ + +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_attestation_ca.pb.h" + +namespace enterprise_connector { + +// A class which provides helpers for cryptography-related tasks. +class CryptoUtility { + public: + // Verifies a PKCS #1 v1.5 SHA-256 |signature| over |data| with digest + // algorithm |digest_nid|. The |public_key_hex| contains a modulus in hex + // format. + static bool VerifySignatureUsingHexKey( + const std::string& public_key_modulus_hex, + const std::string& data, + const std::string& signature); +}; + +} // namespace enterprise_connector + +#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_CRYPTO_UTILITY_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc index d2c28d1..8cccc4d 100644 --- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc +++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
@@ -11,27 +11,21 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/enterprise/connectors/connectors_prefs.h" -#include "chrome/browser/enterprise/connectors/device_trust/attestation_ca.pb.h" -#include "chrome/browser/enterprise/connectors/device_trust/interface.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_attestation_ca.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_interface.pb.h" #include "chrome/browser/enterprise/connectors/device_trust/signal_reporter.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" namespace enterprise_connectors { -DeviceTrustService::DeviceTrustService() = default; - DeviceTrustService::DeviceTrustService(Profile* profile) : prefs_(profile->GetPrefs()), first_report_sent_(false), signal_report_callback_( base::BindOnce(&DeviceTrustService::OnSignalReported, base::Unretained(this))) { -#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - key_pair_ = std::make_unique<DeviceTrustKeyPair>(); -#endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - - attestation_service_ = std::make_unique<attestation::AttestationService>(); + attestation_service_ = std::make_unique<AttestationService>(); pref_observer_.Init(prefs_); pref_observer_.Add(kContextAwareAccessSignalsAllowlistPref, base::BindRepeating(&DeviceTrustService::OnPolicyUpdated, @@ -69,9 +63,6 @@ } if (!first_report_sent_ && IsEnabled()) { // Policy enabled for the 1st time. -#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - key_pair_->Init(); -#endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) reporter_->Init(MakePolicyCheck(), base::BindOnce(&DeviceTrustService::OnReporterInitialized, weak_factory_.GetWeakPtr())); @@ -95,7 +86,7 @@ auto* credential = report.mutable_attestation_credential(); credential->set_format( DeviceTrustReportEvent::Credential::EC_NID_X9_62_PRIME256V1_PUBLIC_DER); - credential->set_credential(key_pair_->ExportPEMPublicKey()); + credential->set_credential(attestation_service_->ExportPEMPublicKey()); #endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) reporter_->SendReport(&report, std::move(signal_report_callback_)); @@ -128,21 +119,14 @@ #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) std::string DeviceTrustService::GetAttestationCredentialForTesting() const { - return key_pair_->ExportPEMPublicKey(); + return attestation_service_->ExportPEMPublicKey(); } #endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) -std::string DeviceTrustService::BuildChallengeResponse( - const std::string& challenge) { - ::attestation::SignEnterpriseChallengeRequest request; - ::attestation::SignEnterpriseChallengeReply result; - // Get the challenge from the SignedData json and create request. - request.set_challenge( - attestation_service_->JsonChallengeToProtobufChallenge(challenge)); - attestation_service_->SignEnterpriseChallenge(request, &result); - - return attestation_service_->ProtobufChallengeToJsonChallenge( - result.challenge_response()); +void DeviceTrustService::BuildChallengeResponse(const std::string& challenge, + AttestationCallback callback) { + attestation_service_->BuildChallengeResponseForVAChallenge( + challenge, std::move(callback)); } } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h index 40a0698..c0b81b8 100644 --- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h +++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
@@ -10,15 +10,10 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/policy/core/browser/configuration_policy_handler.h" #include "components/prefs/pref_change_registrar.h" -#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include <memory> -#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) -#include "chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h" -#endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - class KeyedService; class Profile; class PrefService; @@ -30,8 +25,12 @@ class DeviceTrustService : public KeyedService { public: + using AttestationCallback = base::OnceCallback<void(const std::string&)>; + + DeviceTrustService() = delete; DeviceTrustService(const DeviceTrustService&) = delete; DeviceTrustService& operator=(const DeviceTrustService&) = delete; + ~DeviceTrustService() override; // Check if DeviceTrustService is enabled via prefs with non-empty allowlist. bool IsEnabled() const; @@ -48,14 +47,13 @@ // Starts flow that actually builds a response. This method is called // from a non_UI thread. - std::string BuildChallengeResponse(const std::string& challenge); + void BuildChallengeResponse(const std::string& challenge, + AttestationCallback callback); private: friend class DeviceTrustFactory; - DeviceTrustService(); explicit DeviceTrustService(Profile* profile); - ~DeviceTrustService() override; void Shutdown() override; @@ -67,16 +65,12 @@ PrefService* prefs_; -#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - std::unique_ptr<DeviceTrustKeyPair> key_pair_; -#endif // defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MAC) - PrefChangeRegistrar pref_observer_; bool first_report_sent_; std::unique_ptr<enterprise_connectors::DeviceTrustSignalReporter> reporter_; SignalReportCallback signal_report_callback_; - std::unique_ptr<attestation::AttestationService> attestation_service_; + std::unique_ptr<AttestationService> attestation_service_; base::WeakPtrFactory<DeviceTrustService> weak_factory_{this}; };
diff --git a/chrome/browser/enterprise/connectors/device_trust/google_keys.cc b/chrome/browser/enterprise/connectors/device_trust/google_keys.cc new file mode 100644 index 0000000..77e0229 --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/google_keys.cc
@@ -0,0 +1,81 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/device_trust/google_keys.h" + +#include <base/logging.h> + +namespace enterprise_connectors { + +namespace { +// VA server instance for prod. +// http://test-dvproxy-server.sandbox.google.com +constexpr char kDefaultVASigningPublicKey[] = + "bf7fefa3a661437b26aed0801db64d7ba8b58875c351d3bdc9f653847d4a67b3" + "b67479327724d56aa0f71a3f57c2290fdc1ff05df80589715e381dfbbda2c4ac" + "114c30d0a73c5b7b2e22178d26d8b65860aa8dd65e1b3d61a07c81de87c1e7e4" + "590145624936a011ece10434c1d5d41f917c3dc4b41dd8392479130c4fd6eafc" + "3bb4e0dedcc8f6a9c28428bf8fbba8bd6438a325a9d3eabee1e89e838138ad99" + "69c292c6d9f6f52522333b84ddf9471ffe00f01bf2de5faa1621f967f49e158b" + "f2b305360f886826cc6fdbef11a12b2d6002d70d8d1e8f40e0901ff94c203cb2" + "01a36a0bd6e83955f14b494f4f2f17c0c826657b85c25ffb8a73599721fa17ab"; +constexpr char kDefaultVAEncryptionPublicKey[] = + "edba5e723da811e41636f792c7a77aef633fbf39b542aa537c93c93eaba7a3b1" + "0bc3e484388c13d625ef5573358ec9e7fbeb6baaaa87ca87d93fb61bf5760e29" + "6813c435763ed2c81f631e26e3ff1a670261cdc3c39a4640b6bbf4ead3d6587b" + "e43ef7f1f08e7596b628ec0b44c9b7ad71c9ee3a1258852c7a986c7614f0c4ec" + "f0ce147650a53b6aa9ae107374a2d6d4e7922065f2f6eb537a994372e1936c87" + "eb08318611d44daf6044f8527687dc7ce5319b51eae6ab12bee6bd16e59c499e" + "fa53d80232ae886c7ee9ad8bc1cbd6e4ac55cb8fa515671f7e7ad66e98769f52" + "c3c309f98bf08a3b8fbb0166e97906151b46402217e65c5d01ddac8514340e8b"; + +// VA server instance for QA. +// https://qa-dvproxy-server-gws.sandbox.google.com +constexpr char kTestVASigningPublicKey[] = + "baab3e277518c65b1b98290bb55061df9a50b9f32a4b0ff61c7c61c51e966fcd" + "c891799a39ee0b7278f204a2b45a7e615080ff8f69f668e05adcf3486b319f80" + "f9da814d9b86b16a3e68b4ce514ab5591112838a68dc3bfdcc4043a5aa8de52c" + "ae936847a271971ecaa188172692c13f3b0321239c90559f3b7ba91e66d38ef4" + "db4c75104ac5f2f15e55a463c49753a88e56906b1725fd3f0c1372beb16d4904" + "752c74452b0c9f757ee12877a859dd0666cafaccbfc33fe67d98a89a2c12ef52" + "5e4b16ea8972577dbfc567c2625a3eee6bcaa6cb4939b941f57236d1d57243f8" + "c9766938269a8034d82fbd44044d2ee6a5c7275589afc3790b60280c0689900f"; +constexpr char kTestVAEncryptionPublicKey[] = + "c0c116e7ded8d7c1e577f9c8fb0d267c3c5c3e3b6800abb0309c248eaa5cd9bf" + "91945132e4bb0111711356a388b756788e20bc1ecc9261ea9bcae8369cfd050e" + "d8dc00b50fbe36d2c1c8a9b335f2e11096be76bebce8b5dcb0dc39ac0fd963b0" + "51474f794d4289cc0c52d0bab451b9e69a43ecd3a84330b0b2de4365c038ffce" + "ec0f1999d789615849c2f3c29d1d9ed42ccb7f330d5b56f40fb7cc6556190c3b" + "698c20d83fb341a442fd69701fe0bdc41bdcf8056ccbc8d9b4275e8e43ec6b63" + "c1ae70d52838dfa90a9cd9e7b6bd88ed3abf4fab444347104e30e635f4f296ac" + "4c91939103e317d0eca5f36c48102e967f176a19a42220f3cf14634b6773be07"; + +} // namespace + +GoogleKeys ::GoogleKeys() { + // No key_id for signing key. + va_signing_keys_[DEFAULT_VA].set_modulus_in_hex(kDefaultVASigningPublicKey); + va_signing_keys_[TEST_VA].set_modulus_in_hex(kTestVASigningPublicKey); + + va_encryption_keys_[DEFAULT_VA].set_modulus_in_hex( + kDefaultVAEncryptionPublicKey); + va_encryption_keys_[TEST_VA].set_modulus_in_hex(kTestVAEncryptionPublicKey); +} + +GoogleKeys::GoogleKeys(const DefaultGoogleRsaPublicKeySet& default_key_set) + : GoogleKeys() { + va_signing_keys_[DEFAULT_VA] = default_key_set.default_va_signing_key(); + va_encryption_keys_[DEFAULT_VA] = default_key_set.default_va_encryption_key(); +} + +GoogleKeys::~GoogleKeys() = default; + +const GoogleRsaPublicKey& GoogleKeys::va_signing_key(VAType va_type) const { + return va_signing_keys_[va_type]; +} +const GoogleRsaPublicKey& GoogleKeys::va_encryption_key(VAType va_type) const { + return va_encryption_keys_[va_type]; +} + +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/google_keys.h b/chrome/browser/enterprise/connectors/device_trust/google_keys.h new file mode 100644 index 0000000..2b7babaf --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/google_keys.h
@@ -0,0 +1,40 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_GOOGLE_KEYS_H_ +#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_GOOGLE_KEYS_H_ + +#include <array> +#include <string> + +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_google_key.pb.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_interface.pb.h" + +namespace enterprise_connectors { + +// A class that manages the public keys along with their key IDs the attestation +// service uses. +class GoogleKeys { + public: + GoogleKeys(); + explicit GoogleKeys(const DefaultGoogleRsaPublicKeySet& default_key_set); + ~GoogleKeys(); + + // Copyable and movable with the default behavior. + GoogleKeys(const GoogleKeys&); + GoogleKeys& operator=(const GoogleKeys&) = default; + GoogleKeys(GoogleKeys&&); + GoogleKeys& operator=(GoogleKeys&&) = default; + + const GoogleRsaPublicKey& va_signing_key(VAType va_type) const; + const GoogleRsaPublicKey& va_encryption_key(VAType va_type) const; + + private: + std::array<GoogleRsaPublicKey, VAType_ARRAYSIZE> va_signing_keys_; + std::array<GoogleRsaPublicKey, VAType_ARRAYSIZE> va_encryption_keys_; +}; + +} // namespace enterprise_connectors + +#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_GOOGLE_KEYS_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc index 09e4182..f485eedb 100644 --- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc +++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc
@@ -5,14 +5,12 @@ #include "chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h" #include "base/memory/ptr_util.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/enterprise/connectors/connectors_prefs.h" #include "chrome/browser/enterprise/connectors/device_trust/device_trust_factory.h" +#include "chrome/browser/enterprise/connectors/device_trust/device_trust_interface.pb.h" #include "chrome/browser/enterprise/connectors/device_trust/device_trust_service.h" -#include "chrome/browser/enterprise/connectors/device_trust/interface.pb.h" #include "chrome/browser/profiles/profile.h" #include "components/policy/core/browser/url_util.h" #include "components/prefs/pref_service.h" @@ -135,40 +133,37 @@ std::string challenge; if (headers->GetNormalizedHeader(kVerifiedAccessChallengeHeader, &challenge)) { - // Post a task to get the challenge response. It will defer the navigation - // and it will be resumed after it's built. - // `StartSignChallengeAndReplyWithResponse` won't run in the main thread, - // and then reply to `ReplyChallengeResponseAndResume` which makes use of - // `weak_ptr_factory_.GetWeakPtr()` so it won't run in case the object is - // destroyed. - AttestationCallback reply = base::BindOnce( + // Create callback for `ReplyChallengeResponseAndResume` which will + // be called after the challenge response is created. With this + // we can defer the navigation to unblock the main thread. + AttestationCallback resume_navigation_callback = base::BindOnce( &DeviceTrustNavigationThrottle::ReplyChallengeResponseAndResume, weak_ptr_factory_.GetWeakPtr()); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, - base::BindOnce(&DeviceTrustNavigationThrottle:: - StartSignChallengeAndReplyWithResponse, - base::Unretained(this), challenge), - std::move(reply)); + // Call `DeviceTrustService::BuildChallengeResponse` which is one step on + // the chain that builds the challenge response. In this chain we post a + // task that won't run in the main thread. + device_trust_service_->BuildChallengeResponse( + challenge, std::move(resume_navigation_callback)); return DEFER; } + } else { + LOG(ERROR) << "No challenge in the response."; } return PROCEED; } -std::string -DeviceTrustNavigationThrottle::StartSignChallengeAndReplyWithResponse( - const std::string& challenge) { - return device_trust_service_->BuildChallengeResponse(challenge); -} - void DeviceTrustNavigationThrottle::ReplyChallengeResponseAndResume( - std::string challenge_response) { - navigation_handle()->SetRequestHeader(kVerifiedAccessResponseHeader, - challenge_response); - Resume(); + const std::string& challenge_response) { + if (challenge_response == std::string()) { + // Cancel the navigation if challenge signature is invalid. + CancelDeferredNavigation(content::NavigationThrottle::CANCEL_AND_IGNORE); + } else { + navigation_handle()->SetRequestHeader(kVerifiedAccessResponseHeader, + challenge_response); + Resume(); + } } } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h index ddb946a..5c6ba398 100644 --- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h +++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h
@@ -34,7 +34,7 @@ static std::unique_ptr<DeviceTrustNavigationThrottle> MaybeCreateThrottleFor( content::NavigationHandle* navigation_handle); - using AttestationCallback = base::OnceCallback<void(std::string)>; + using AttestationCallback = base::OnceCallback<void(const std::string&)>; explicit DeviceTrustNavigationThrottle( content::NavigationHandle* navigation_handle); @@ -61,13 +61,7 @@ // Set `challege_response` into the header // `X-Verified-Access-Challenge-Response` of the redirection request to the // IdP and resume the navigation. - void ReplyChallengeResponseAndResume(std::string challenge_response); - - // Call `DeviceTrustService::BuildChallengeResponse` which is the method that - // actually builds the challenge response, and return it as a string with the - // format described in `AttestationService::ProtobufChallengeToJsonChallenge`. - std::string StartSignChallengeAndReplyWithResponse( - const std::string& challenge); + void ReplyChallengeResponseAndResume(const std::string& challenge_response); // The URL matcher created from the ContextAwareAccessSignalsAllowlist policy. std::unique_ptr<url_matcher::URLMatcher> matcher_;
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc index 2546dfd8..7befb7f2 100644 --- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc +++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle_unittest.cc
@@ -14,6 +14,7 @@ #include "content/public/browser/navigation_throttle.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_navigation_handle.h" +#include "net/http/http_response_headers.h" #include "testing/gtest/include/gtest/gtest.h" using content::NavigationThrottle; @@ -23,6 +24,22 @@ const base::Value kOrigins[]{base::Value("https://www.example.com"), base::Value("example2.example.com")}; +constexpr char challenge[] = + "{" + "\"challenge\": {" + " \"data\": " + "\"ChZFbnRlcnByaXNlS2V5Q2hhbGxlbmdlEiB+CPt6kzZVCmxIPc4K5NdVGsTLYVcA0ekaCVq+" + "8KbZEBif4oXClC8=\"," + " \"signature\": " + "\"TiR/Qd/f+V/XFnYPIqeLO6/AXI+SKOnKGJmqhJd06MjnHhRnCK5u/BdFkq2H5U/" + "qqAx4DS6SfcLfJ+6NEdsemn/5UTmarOOxWA8Fh2zc2a2Zr1+MGDdgRkckIzA5iw99/" + "EV+xIUXyVaqJjSuD9iPSFJzlJUtlhbijf8JT1w8PuuxNOERuhqIrJvpZFpb+" + "u99YLuGrpw7y64Bh6AhsXryGjowqXYojYWAOYeHX4b2axkHDsThybI+v+" + "ECtVHi3l6Z2TOwr7fkyhoy1Kz9swd30rw6/VDB92jzrJTQoy3rQ2+aY8KxycU/" + "nuJn3H6583SsiaTbKgyHKmObbGdt0GVWLQ==\"" + "}" + "}"; + } // namespace namespace enterprise_connectors { @@ -78,4 +95,27 @@ EXPECT_EQ(NavigationThrottle::PROCEED, throttle->WillStartRequest().action()); } +scoped_refptr<net::HttpResponseHeaders> GetHeaderChallenge( + const std::string& challenge) { + std::string raw_response_headers = + "HTTP/1.1 200 OK\r\n" + "x-verified-access-challenge: " + + challenge + "\r\n"; + return base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders(raw_response_headers)); +} + +TEST_F(DeviceTrustNavigationThrottleTest, BuildChallengeResponseFromHeader) { + EnableDeviceTrust(); + GURL url("https://www.example.com/"); + content::MockNavigationHandle test_handle(url, main_rfh()); + + test_handle.set_response_headers(GetHeaderChallenge(challenge)); + auto throttle = + DeviceTrustNavigationThrottle::MaybeCreateThrottleFor(&test_handle); + ASSERT_TRUE(throttle); + + EXPECT_EQ(NavigationThrottle::DEFER, throttle->WillStartRequest().action()); +} + } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc index 83760c6..06ee7fa 100644 --- a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc +++ b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc
@@ -397,7 +397,6 @@ : folder_id_(folder_id), target_file_name_(target_file_name), local_file_path_(local_file_path), - file_mime_type_(GetMimeType(target_file_name)), multipart_boundary_(net::GenerateMimeMultipartBoundary()), callback_(std::move(callback)) {} @@ -406,12 +405,6 @@ void BoxWholeFileUploadApiCallFlow::Start( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& access_token) { - // Ensure that file extension was valid and file type was obtained. - if (file_mime_type_.empty()) { - DLOG(ERROR) << "Couldn't obtain proper file type for " << target_file_name_; - std::move(callback_).Run(false, 0, GURL()); - } - // Forward the arguments via PostReadFileTask() then OnFileRead() into // OAuth2CallFlow::Start(). PostReadFileTask(url_loader_factory, access_token); @@ -421,7 +414,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& access_token) { auto read_file_task = base::BindOnce(&BoxWholeFileUploadApiCallFlow::ReadFile, - local_file_path_); + local_file_path_, target_file_name_); auto read_file_reply = base::BindOnce( &BoxWholeFileUploadApiCallFlow::OnFileRead, weak_factory_.GetWeakPtr(), url_loader_factory, access_token); @@ -431,27 +424,35 @@ std::move(read_file_task), std::move(read_file_reply)); } -absl::optional<std::string> BoxWholeFileUploadApiCallFlow::ReadFile( - const base::FilePath& path) { - std::string content; - return base::ReadFileToStringWithMaxSize(path, &content, - kWholeFileUploadMaxSize) - ? absl::optional<std::string>(std::move(content)) - : absl::nullopt; +// static +absl::optional<BoxWholeFileUploadApiCallFlow::FileRead> +BoxWholeFileUploadApiCallFlow::ReadFile( + const base::FilePath& path, + const base::FilePath& target_file_name) { + FileRead file_read; + file_read.mime = GetMimeType(target_file_name); + if (file_read.mime.empty() || // Ensure that file extension was valid. + !base::ReadFileToStringWithMaxSize(path, &file_read.content, + kWholeFileUploadMaxSize)) { + DLOG(ERROR) << "File " << path << " with target name " << target_file_name; + return absl::nullopt; + } + DCHECK_LE(file_read.content.size(), kWholeFileUploadMaxSize); + return absl::optional<FileRead>(std::move(file_read)); } void BoxWholeFileUploadApiCallFlow::OnFileRead( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& access_token, - absl::optional<std::string> file_read) { + absl::optional<FileRead> file_read) { if (!file_read) { DLOG(ERROR) << "[BoxApiCallFlow] WholeFileUpload read file failed"; // TODO(https://crbug.com/1165972): error handling std::move(callback_).Run(false, 0, GURL()); return; } - DCHECK_LE(file_read->size(), kWholeFileUploadMaxSize); - file_content_ = std::move(*file_read); + DCHECK_LE(file_read->content.size(), kWholeFileUploadMaxSize); + file_read_ = std::move(*file_read); // Continue to the original call flow after file has been read. OAuth2ApiCallFlow::Start(url_loader_factory, access_token); @@ -464,7 +465,7 @@ std::string BoxWholeFileUploadApiCallFlow::CreateApiCallBody() { CHECK(!folder_id_.empty()); CHECK(!target_file_name_.empty()); - CHECK(!file_mime_type_.empty()); + CHECK(!file_read_.mime.empty()) << target_file_name_; CHECK(!multipart_boundary_.empty()); base::Value attr(base::Value::Type::DICTIONARY); @@ -479,8 +480,8 @@ "application/json", &body); net::AddMultipartValueForUploadWithFileName( - "file", target_file_name_.MaybeAsASCII(), file_content_, - multipart_boundary_, file_mime_type_, &body); + "file", target_file_name_.MaybeAsASCII(), file_read_.content, + multipart_boundary_, file_read_.mime, &body); net::AddMultipartFinalDelimiterForUpload(multipart_boundary_, &body); return body; @@ -516,6 +517,13 @@ std::move(callback_).Run(false, response_code, GURL()); } +void BoxWholeFileUploadApiCallFlow::SetFileReadForTesting( + std::string content, + std::string mime_type) { + file_read_.content = std::move(content); + file_read_.mime = std::move(mime_type); +} + //////////////////////////////////////////////////////////////////////////////// // ChunkedUpload: CreateUploadSession ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.h b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.h index add472e..cf1a213 100644 --- a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.h +++ b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow.h
@@ -157,32 +157,38 @@ const network::mojom::URLResponseHead* head, std::unique_ptr<std::string> body) override; + void SetFileReadForTesting(std::string content, std::string mime_type); + private: + struct FileRead { + std::string content; + std::string mime; + }; // Post a task to ThreadPool to read the local file, forward the // parameters from Start() into OnFileRead(), which is the callback that then // kicks off OAuth2CallFlow::Start() after file content is read. void PostReadFileTask( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& access_token); - - // Helper functions to read and delete the local file. - // Task posted to ThreadPool to read the local file. Return type is - // absl::optional in case file is read successfully but the file content is - // really empty. - static absl::optional<std::string> ReadFile(const base::FilePath& path); // Callback attached in PostReadFileTask(). Take in read file content and // kick off OAuth2CallFlow::Start(). void OnFileRead( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& access_token, - absl::optional<std::string> content); + absl::optional<FileRead> file_read); + + // Task posted to ThreadPool to read the local file. Return type is + // base::Optional in case file is read successfully but the file content is + // really empty. + static absl::optional<FileRead> ReadFile( + const base::FilePath& path, + const base::FilePath& target_file_name); const std::string folder_id_; const base::FilePath target_file_name_; const base::FilePath local_file_path_; - const std::string file_mime_type_; const std::string multipart_boundary_; - std::string file_content_; + FileRead file_read_; // Callback from the uploader to report success. TaskCallback callback_;
diff --git a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow_unittest.cc b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow_unittest.cc index ec44371..09ba13f 100644 --- a/chrome/browser/enterprise/connectors/file_system/box_api_call_flow_unittest.cc +++ b/chrome/browser/enterprise/connectors/file_system/box_api_call_flow_unittest.cc
@@ -17,7 +17,6 @@ #include "base/strings/stringprintf.h" #include "base/test/task_environment.h" #include "chrome/browser/enterprise/connectors/file_system/box_api_call_test_helper.h" -#include "net/base/mime_util.h" #include "net/base/net_errors.h" #include "net/http/http_status_code.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" @@ -338,6 +337,7 @@ using BoxWholeFileUploadApiCallFlow::IsExpectedSuccessCode; using BoxWholeFileUploadApiCallFlow::ProcessApiCallFailure; using BoxWholeFileUploadApiCallFlow::ProcessApiCallSuccess; + using BoxWholeFileUploadApiCallFlow::SetFileReadForTesting; }; class BoxWholeFileUploadApiCallFlowTest @@ -361,10 +361,43 @@ std::move(quit_closure_).Run(); } - std::string folder_id_{"13579"}; + std::string MakeExpectedBody() { + // Body format for multipart/form-data reference: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + // Request body fields reference: + // https://developer.box.com/reference/post-files-content/ + std::string content_type = flow_->CreateApiCallBodyContentType(); + std::string expected_type("multipart/form-data; boundary="); + + std::string multipart_boundary = + "--" + content_type.substr(expected_type.size()); + std::string expected_body(multipart_boundary + "\r\n"); + expected_body += + "Content-Disposition: form-data; name=\"attributes\"\r\n" + "Content-Type: application/json\r\n\r\n" + "{\"name\":\""; + expected_body += + file_name_.AsUTF8Unsafe() + // AsUTF8Unsafe() to compile on Windows + "\"," + "\"parent\":{\"id\":\"" + + folder_id_ + "\"}}\r\n"; + expected_body += multipart_boundary + "\r\n"; + expected_body += + "Content-Disposition: form-data; name=\"file\"; filename=\""; + expected_body += + file_name_.AsUTF8Unsafe() + // AsUTF8Unsafe() to compile on Windows + "\"\r\nContent-Type: " + mime_type_ + "\r\n\r\n"; + expected_body += file_content_ + "\r\n"; + expected_body += multipart_boundary + "--\r\n"; + return expected_body; + } + + base::FilePath file_path_; + const std::string folder_id_{"13579"}; + const std::string mime_type_{"text/plain"}; const base::FilePath file_name_{ FILE_PATH_LITERAL("box_whole_file_upload_test.txt")}; - base::FilePath file_path_; + const std::string file_content_{"<TestContent>~~~123456789~~~</TestContent>"}; GURL file_url_; @@ -385,32 +418,8 @@ std::string expected_type("multipart/form-data; boundary="); ASSERT_EQ(content_type.substr(0, expected_type.size()), expected_type); - // Body format for multipart/form-data reference: - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type - // Request body fields reference: - // https://developer.box.com/reference/post-files-content/ - std::string multipart_boundary = - "--" + content_type.substr(expected_type.size()); - std::string expected_body(multipart_boundary + "\r\n"); - std::string mime_type; - net::GetMimeTypeFromExtension(FILE_PATH_LITERAL("txt"), &mime_type); - expected_body += - "Content-Disposition: form-data; name=\"attributes\"\r\n" - "Content-Type: application/json\r\n\r\n" - "{\"name\":\""; - expected_body += - file_name_.AsUTF8Unsafe() + // AsUTF8Unsafe() to compile on Windows - "\"," - "\"parent\":{\"id\":\"" + - folder_id_ + "\"}}\r\n"; - expected_body += multipart_boundary + "\r\n"; - expected_body += "Content-Disposition: form-data; name=\"file\"; filename=\""; - expected_body += - file_name_.AsUTF8Unsafe() + // AsUTF8Unsafe() to compile on Windows - "\"\r\nContent-Type: " + mime_type + "\r\n\r\n\r\n"; - expected_body += multipart_boundary + "--\r\n"; - std::string body = flow_->CreateApiCallBody(); - ASSERT_EQ(body, expected_body); + flow_->SetFileReadForTesting(file_content_, mime_type_); + ASSERT_EQ(flow_->CreateApiCallBody(), MakeExpectedBody()); } TEST_F(BoxWholeFileUploadApiCallFlowTest, IsExpectedSuccessCode) { @@ -514,17 +523,29 @@ BoxWholeFileUploadApiCallFlowFileReadTest() : url_factory_( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_)) {} + &test_url_loader_factory_)) { + test_url_loader_factory_.SetInterceptor(base::BindRepeating( + &BoxWholeFileUploadApiCallFlowFileReadTest::VerifyRequest, + base::Unretained(this))); + } protected: + void VerifyRequest(const network::ResourceRequest& request) { + ASSERT_EQ(request.url, kFileSystemBoxDirectUploadUrl); + // Check that file was read and formatted into request body string properly, + // without going down the rabbit hole of request.request_body->elements()-> + // front().As<network::DataElementBytes>().AsStringPiece(). + ASSERT_EQ(flow_->CreateApiCallBody(), MakeExpectedBody()); + ++request_sent_count_; + } + + size_t request_sent_count_ = 0; network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> url_factory_; }; TEST_F(BoxWholeFileUploadApiCallFlowFileReadTest, GoodUpload) { - ASSERT_TRUE( - base::WriteFile(file_path_, "BoxWholeFileUploadApiCallFlowFileReadTest")) - << file_path_; + ASSERT_TRUE(base::WriteFile(file_path_, file_content_)) << file_path_; test_url_loader_factory_.AddResponse(kFileSystemBoxDirectUploadUrl, std::string(), net::HTTP_CREATED); @@ -532,9 +553,10 @@ base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); - flow_->Start(url_factory_, "dummytoken"); + flow_->Start(url_factory_, "test_token"); run_loop.Run(); + ASSERT_EQ(request_sent_count_, 1U); ASSERT_EQ(response_code_, net::HTTP_CREATED); ASSERT_TRUE(processed_success_) << "Failed with file " << file_path_; ASSERT_TRUE(base::PathExists(file_path_)) @@ -548,11 +570,12 @@ base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); - flow_->Start(url_factory_, "dummytoken"); + flow_->Start(url_factory_, "test_token"); run_loop.Run(); - // There should be no HTTP response code, because it should already fail when - // reading file, before making any actual API calls. + // Because file read already failed before any actual API calls are made, + // there should be no API calls made, and therefore no HTTP response code. + ASSERT_EQ(request_sent_count_, 0U); ASSERT_EQ(response_code_, 0); ASSERT_FALSE(processed_success_); }
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc index 87ac6ad..0fa6ecd0 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -505,8 +505,9 @@ } void DeveloperPrivateEventRouter::OnExtensionManagementSettingsChanged() { - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->Append(DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue()); + std::vector<base::Value> args; + args.push_back(base::Value::FromUniquePtrValue( + DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue())); std::unique_ptr<Event> event( new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED, @@ -533,8 +534,9 @@ } void DeveloperPrivateEventRouter::OnProfilePrefChanged() { - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->Append(DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue()); + std::vector<base::Value> args; + args.push_back(base::Value::FromUniquePtrValue( + DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue())); std::unique_ptr<Event> event( new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED, developer::OnProfileStateChanged::kEventName, std::move(args))); @@ -587,8 +589,8 @@ std::make_unique<developer::ExtensionInfo>(std::move(infos[0])); } - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->Append(event_data.ToValue()); + std::vector<base::Value> args; + args.push_back(base::Value::FromUniquePtrValue(event_data.ToValue())); std::unique_ptr<Event> event( new Event(events::DEVELOPER_PRIVATE_ON_ITEM_STATE_CHANGED, developer::OnItemStateChanged::kEventName, std::move(args)));
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc index 26808fa..a443710 100644 --- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc +++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -331,8 +331,8 @@ GetDriveMountPoint().AppendASCII("root/open_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE(RunExtensionTest({.name = "api_test/file_system/open_existing", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/open_existing", + {.launch_as_platform_app = true})) << message_; } @@ -342,9 +342,8 @@ GetDriveMountPoint().AppendASCII("root/open_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE( - RunExtensionTest({.name = "api_test/file_system/open_existing_with_write", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/open_existing_with_write", + {.launch_as_platform_app = true})) << message_; } @@ -355,9 +354,9 @@ ASSERT_TRUE(base::PathService::OverrideAndCreateIfNeeded( chrome::DIR_USER_DOCUMENTS, test_file.DirName(), true, false)); FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest(); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/open_multiple_with_suggested_name", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/open_multiple_with_suggested_name", + {.launch_as_platform_app = true})) << message_; } @@ -372,9 +371,8 @@ test_files.push_back(test_file2); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( &test_files); - ASSERT_TRUE( - RunExtensionTest({.name = "api_test/file_system/open_multiple_existing", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/open_multiple_existing", + {.launch_as_platform_app = true})) << message_; } @@ -384,8 +382,8 @@ GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); - ASSERT_TRUE(RunExtensionTest({.name = "api_test/file_system/open_directory", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/open_directory", + {.launch_as_platform_app = true})) << message_; } @@ -395,9 +393,8 @@ GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/open_directory_with_write", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/open_directory_with_write", + {.launch_as_platform_app = true})) << message_; } @@ -407,9 +404,9 @@ GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/open_directory_without_permission", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/open_directory_without_permission", + {.launch_as_platform_app = true})) << message_; } @@ -419,9 +416,9 @@ GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/open_directory_with_only_write", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/open_directory_with_only_write", + {.launch_as_platform_app = true})) << message_; } @@ -431,8 +428,8 @@ GetDriveMountPoint().AppendASCII("root/save_new.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE(RunExtensionTest({.name = "api_test/file_system/save_new", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/save_new", + {.launch_as_platform_app = true})) << message_; } @@ -442,8 +439,8 @@ GetDriveMountPoint().AppendASCII("root/save_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE(RunExtensionTest({.name = "api_test/file_system/save_existing", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/save_existing", + {.launch_as_platform_app = true})) << message_; } @@ -453,9 +450,8 @@ GetDriveMountPoint().AppendASCII("root/save_new.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE( - RunExtensionTest({.name = "api_test/file_system/save_new_with_write", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/save_new_with_write", + {.launch_as_platform_app = true})) << message_; } @@ -465,53 +461,52 @@ GetDriveMountPoint().AppendASCII("root/save_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); - ASSERT_TRUE( - RunExtensionTest({.name = "api_test/file_system/save_existing_with_write", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/save_existing_with_write", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, Background) { EnterKioskSession(); ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_OK); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_background", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/request_file_system_background", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, ReadOnly) { EnterKioskSession(); ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_OK); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_read_only", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/request_file_system_read_only", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, Writable) { EnterKioskSession(); ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_OK); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_writable", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/request_file_system_writable", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, UserReject) { EnterKioskSession(); ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_CANCEL); - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_user_reject", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/request_file_system_user_reject", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, NotKioskSession) { ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_OK); ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_not_kiosk_session", - .launch_as_platform_app = true})) + "api_test/file_system/request_file_system_not_kiosk_session", + {.launch_as_platform_app = true})) << message_; } @@ -519,9 +514,8 @@ AllowlistedComponent) { ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_CANCEL); ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_file_system_whitelisted_component", - .launch_as_platform_app = true}, - {.load_as_component = true})) + "api_test/file_system/request_file_system_whitelisted_component", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } @@ -529,25 +523,23 @@ NotAllowlistedComponent) { ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_OK); ASSERT_TRUE(RunExtensionTest( - {.name = - "api_test/file_system/request_file_system_not_whitelisted_component", - .launch_as_platform_app = true}, - {.load_as_component = true})) + "api_test/file_system/request_file_system_not_whitelisted_component", + {.launch_as_platform_app = true}, {.load_as_component = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, GetVolumeList) { EnterKioskSession(); - ASSERT_TRUE(RunExtensionTest({.name = "api_test/file_system/get_volume_list", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/get_volume_list", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem, GetVolumeList_NotKioskSession) { - ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/get_volume_list_not_kiosk_session", - .launch_as_platform_app = true})) + ASSERT_TRUE( + RunExtensionTest("api_test/file_system/get_volume_list_not_kiosk_session", + {.launch_as_platform_app = true})) << message_; } @@ -561,9 +553,8 @@ base::BindOnce(&FileSystemApiTestForRequestFileSystem::MountFakeVolume, base::Unretained(this))); - ASSERT_TRUE( - RunExtensionTest({.name = "api_test/file_system/on_volume_list_changed", - .launch_as_platform_app = true})) + ASSERT_TRUE(RunExtensionTest("api_test/file_system/on_volume_list_changed", + {.launch_as_platform_app = true})) << message_; } @@ -571,8 +562,8 @@ AllowlistedExtensionForDownloads) { ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_CANCEL); ASSERT_TRUE(RunExtensionTest( - {.name = "api_test/file_system/request_downloads_whitelisted_extension", - .launch_as_platform_app = true})) + "api_test/file_system/request_downloads_whitelisted_extension", + {.launch_as_platform_app = true})) << message_; }
diff --git a/chrome/browser/extensions/api/notifications/extension_notification_handler.cc b/chrome/browser/extensions/api/notifications/extension_notification_handler.cc index 97c0834..dec81253 100644 --- a/chrome/browser/extensions/api/notifications/extension_notification_handler.cc +++ b/chrome/browser/extensions/api/notifications/extension_notification_handler.cc
@@ -131,7 +131,7 @@ return; std::unique_ptr<Event> event( - new Event(histogram_value, event_name, std::move(args))); + new Event(histogram_value, event_name, args->TakeList())); event->user_gesture = user_gesture; event_router->DispatchEventToExtension(extension_id, std::move(event)); }
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc index efb17bf..a48be71 100644 --- a/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc +++ b/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc
@@ -76,8 +76,8 @@ params.status = status; params.folder_name = std::make_unique<std::string>(std::move(folder_name)); - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(params.ToValue()); + std::vector<base::Value> event_value; + event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue())); auto extension_event = std::make_unique<Event>( events::PASSWORDS_PRIVATE_ON_PASSWORDS_FILE_EXPORT_PROGRESS,
diff --git a/chrome/browser/extensions/api/resources_private/resources_private_api.cc b/chrome/browser/extensions/api/resources_private/resources_private_api.cc index abaa862..f799b14 100644 --- a/chrome/browser/extensions/api/resources_private/resources_private_api.cc +++ b/chrome/browser/extensions/api/resources_private/resources_private_api.cc
@@ -76,14 +76,14 @@ case api::resources_private::COMPONENT_IDENTITY: AddStringsForIdentity(dict.get()); break; + case api::resources_private::COMPONENT_PDF: #if BUILDFLAG(ENABLE_PDF) - case api::resources_private::COMPONENT_PDF: { pdf_extension_util::AddStrings(pdf_extension_util::PdfViewerContext::kAll, dict.get()); pdf_extension_util::AddAdditionalData( IsPdfAnnotationsEnabled(browser_context()), dict.get()); - } break; #endif // BUILDFLAG(ENABLE_PDF) + break; case api::resources_private::COMPONENT_NONE: NOTREACHED(); }
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc index 25b59319..82cbcbd 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -4,16 +4,15 @@ #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" -#include "base/callback_helpers.h" -#include "build/build_config.h" - #include <utility> #include <vector> #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" +#include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_content_browser_client.h" @@ -224,8 +223,8 @@ // |event_router_| can be null in tests. if (event_router_) { - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(params.ToValue()); + std::vector<base::Value> event_value; + event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue())); auto extension_event = std::make_unique<Event>( events:: @@ -256,8 +255,8 @@ const std::string& user_name) { // |event_router_| can be null in tests. if (event_router_) { - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(std::make_unique<base::Value>(user_name)); + std::vector<base::Value> event_value; + event_value.push_back(base::Value(user_name)); auto extension_event = std::make_unique<Event>( events::SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_CHANGED, api::safe_browsing_private::OnPolicySpecifiedPasswordChanged:: @@ -296,8 +295,8 @@ // |event_router_| can be null in tests. if (event_router_) { - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(params.ToValue()); + std::vector<base::Value> event_value; + event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue())); auto extension_event = std::make_unique<Event>( events::SAFE_BROWSING_PRIVATE_ON_DANGEROUS_DOWNLOAD_OPENED, @@ -352,8 +351,8 @@ // |event_router_| can be null in tests. if (event_router_) { - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(params.ToValue()); + std::vector<base::Value> event_value; + event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue())); auto extension_event = std::make_unique<Event>( events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_SHOWN, @@ -401,8 +400,8 @@ // |event_router_| can be null in tests. if (event_router_) { - auto event_value = std::make_unique<base::ListValue>(); - event_value->Append(params.ToValue()); + std::vector<base::Value> event_value; + event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue())); auto extension_event = std::make_unique<Event>( events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_PROCEEDED,
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.cc b/chrome/browser/extensions/api/sessions/sessions_api.cc index 435ab44..fd35f638 100644 --- a/chrome/browser/extensions/api/sessions/sessions_api.cc +++ b/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -624,10 +624,9 @@ void SessionsEventRouter::TabRestoreServiceChanged( sessions::TabRestoreService* service) { - std::unique_ptr<base::ListValue> args(new base::ListValue()); EventRouter::Get(profile_)->BroadcastEvent(std::make_unique<Event>( events::SESSIONS_ON_CHANGED, api::sessions::OnChanged::kEventName, - std::move(args))); + std::vector<base::Value>())); } void SessionsEventRouter::TabRestoreServiceDestroyed(
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc index bcba0980..e79970ab 100644 --- a/chrome/browser/extensions/api/tabs/windows_event_router.cc +++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -304,7 +304,7 @@ std::unique_ptr<Event> event = std::make_unique<Event>( events::WINDOWS_ON_FOCUS_CHANGED, windows::OnFocusChanged::kEventName, - std::make_unique<base::ListValue>()); + std::vector<base::Value>()); event->will_dispatch_callback = base::BindRepeating(&WillDispatchWindowFocusedEvent, window_controller); EventRouter::Get(profile_)->BroadcastEvent(std::move(event));
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc index 2667237..743b9b9f 100644 --- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc +++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -140,10 +140,10 @@ return; } - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->AppendString(terminal_id); - args->AppendString(output_type); - args->AppendString(output); + std::vector<base::Value> args; + args.push_back(base::Value(terminal_id)); + args.push_back(base::Value(output_type)); + args.push_back(base::Value(output)); extensions::EventRouter* event_router = extensions::EventRouter::Get(browser_context); @@ -159,9 +159,8 @@ const std::string& pref_name, extensions::events::HistogramValue histogram, const char* eventName) { - auto args = std::make_unique<base::ListValue>(); - args->Append(base::Value::ToUniquePtrValue( - profile->GetPrefs()->Get(pref_name)->Clone())); + std::vector<base::Value> args; + args.push_back(profile->GetPrefs()->Get(pref_name)->Clone()); extensions::EventRouter* event_router = extensions::EventRouter::Get(profile); if (event_router) { auto event = std::make_unique<extensions::Event>(histogram, eventName,
diff --git a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc index dafc0a9..e601a2b5 100644 --- a/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc +++ b/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
@@ -92,9 +92,9 @@ const std::string& extension_id = extension->id(); if (router->ExtensionHasEventListener(extension_id, kEventName) && extension->permissions_data()->HasAPIPermission("webrtcAudioPrivate")) { - std::unique_ptr<Event> event = std::make_unique<Event>( - events::WEBRTC_AUDIO_PRIVATE_ON_SINKS_CHANGED, kEventName, - std::make_unique<base::ListValue>()); + std::unique_ptr<Event> event = + std::make_unique<Event>(events::WEBRTC_AUDIO_PRIVATE_ON_SINKS_CHANGED, + kEventName, std::vector<base::Value>()); router->DispatchEventToExtension(extension_id, std::move(event)); } }
diff --git a/chrome/browser/extensions/blocklist_states_interaction_unittest.cc b/chrome/browser/extensions/blocklist_states_interaction_unittest.cc index b9a32e6..eb05593c 100644 --- a/chrome/browser/extensions/blocklist_states_interaction_unittest.cc +++ b/chrome/browser/extensions/blocklist_states_interaction_unittest.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/extensions/test_blocklist.h" #include "components/safe_browsing/buildflags.h" #include "extensions/browser/blocklist_state.h" +#include "extensions/common/extension_features.h" #include "testing/gtest/include/gtest/gtest.h" // The interaction tests rely on the safe-browsing database. @@ -27,10 +28,17 @@ // is in the correct extension set under different circumstances. class BlocklistStatesInteractionUnitTest : public ExtensionServiceTestBase { public: + BlocklistStatesInteractionUnitTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kDisablePolicyViolationExtensionsRemotely); + } + void SetUp() override { + ExtensionServiceTestBase::SetUp(); InitializeGoodInstalledExtensionService(); test_blocklist_.Attach(service()->blocklist_); service()->Init(); + extension_prefs_ = ExtensionPrefs::Get(profile()); } protected: @@ -52,8 +60,11 @@ service()->PerformActionBasedOnOmahaAttributes(extension_id, attributes); } + ExtensionPrefs* extension_prefs() { return extension_prefs_; } + private: TestBlocklist test_blocklist_; + ExtensionPrefs* extension_prefs_; }; // 1. The extension is added to the Safe Browsing blocklist with @@ -143,13 +154,12 @@ BLOCKLISTED_POTENTIALLY_UNWANTED); EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); SetOmahaBlocklistStateForExtension(kTestExtensionId, "_malware", true); EXPECT_EQ(BLOCKLISTED_MALWARE, - ExtensionPrefs::Get(profile())->GetExtensionBlocklistState( - kTestExtensionId)); + extension_prefs()->GetExtensionBlocklistState(kTestExtensionId)); EXPECT_TRUE(blocklisted_extensions.Contains(kTestExtensionId)); EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); @@ -164,14 +174,10 @@ // greylist. It will be fixed after we decouple Safe Browsing blocklist state // and Omaha attribute blocklist state. EXPECT_EQ(NOT_BLOCKLISTED, - ExtensionPrefs::Get(profile())->GetExtensionBlocklistState( - kTestExtensionId)); + extension_prefs()->GetExtensionBlocklistState(kTestExtensionId)); EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); - // TODO(crbug.com/1193695): The extension is still disabled with - // DISABLE_GREYLIST reason even though the blocklist state is cleared. This - // should be fixed when we start to consume Omaha attribute greylist. - EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); // The Safe Browsing greylist state should be set correctly after the Safe @@ -179,22 +185,71 @@ SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, BLOCKLISTED_POTENTIALLY_UNWANTED); EXPECT_EQ(BLOCKLISTED_POTENTIALLY_UNWANTED, - ExtensionPrefs::Get(profile())->GetExtensionBlocklistState( - kTestExtensionId)); + extension_prefs()->GetExtensionBlocklistState(kTestExtensionId)); EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); // The extension should be kept disabled because it's still in the Safe // Browsing greylist. EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, NOT_BLOCKLISTED); EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_FALSE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_FALSE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); } +// 1. The extension is added to the Safe Browsing blocklist with +// BLOCKLISTED_MALWARE state. +// 2. The extension is added to the Omaha attribute greylist with +// _policy_violation attribute. +// 3. The extension is removed from the Safe Browsing blocklist. +// 4. The extension is removed from the Omaha attribute greylist. +TEST_F(BlocklistStatesInteractionUnitTest, + SafeBrowsingMalwareThenOmahaAttributePolicyViolation) { + const ExtensionSet& blocklisted_extensions = + registry()->blocklisted_extensions(); + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + const ExtensionSet& disabled_extensions = registry()->disabled_extensions(); + EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(disabled_extensions.Contains(kTestExtensionId)); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, + BLOCKLISTED_MALWARE); + EXPECT_TRUE(blocklisted_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_EQ(BLOCKLISTED_MALWARE, + extension_prefs()->GetExtensionBlocklistState(kTestExtensionId)); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + true); + EXPECT_TRUE(blocklisted_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + extension_prefs())); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, NOT_BLOCKLISTED); + EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); + // The extension should be kept disabled because it's still in the Omaha + // attribute greylist. + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(disabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + EXPECT_EQ(NOT_BLOCKLISTED, + extension_prefs()->GetExtensionBlocklistState(kTestExtensionId)); + EXPECT_TRUE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + extension_prefs())); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + false); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); +} + // 1. The extension is added to the Safe Browsing greylist with // BLOCKLISTED_CWS_POLICY_VIOLATION state. // 2. The extension is added to the Omaha attribute greylist with @@ -209,35 +264,118 @@ SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, BLOCKLISTED_CWS_POLICY_VIOLATION); EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); - // TODO(crbug.com/1180996): Call SetOmahaBlocklistStateForExtension directly - // once we start to consume the _policy_violation attribute. - blocklist_prefs::AddOmahaBlocklistState( - kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, - ExtensionPrefs::Get(profile())); + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + true); EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, NOT_BLOCKLISTED); // The extension should be kept disabled because it's still in the Omaha // attribute greylist. EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_TRUE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_TRUE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); - // TODO(crbug.com/1180996): Call SetOmahaBlocklistStateForExtension directly - // once we start to consume the _policy_violation attribute. - blocklist_prefs::RemoveOmahaBlocklistState( - kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, - ExtensionPrefs::Get(profile())); - service()->ClearGreylistedAcknowledgedStateAndMaybeReenable(kTestExtensionId); + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + false); EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); - EXPECT_FALSE(ExtensionPrefs::Get(profile())->HasDisableReason( + EXPECT_FALSE(extension_prefs()->HasDisableReason( kTestExtensionId, disable_reason::DISABLE_GREYLIST)); } + +// 1. The extension is added to the Omaha attribute greylist with +// BLOCKLISTED_CWS_POLICY_VIOLATION state. +// 2. The extension is added to the Safe Browsing greylist with +// _policy_violation attribute. +// 3. The extension is removed from the Omaha attribute greylist. +// 4. The extension is removed from the Safe Browsing greylist. +TEST_F(BlocklistStatesInteractionUnitTest, + OmahaAttributePolicyViolationThenSafeBrowsingPolicyViolation) { + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + true); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, + BLOCKLISTED_CWS_POLICY_VIOLATION); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + false); + // The extension should be kept disabled because it's still in the Safe + // Browsing greylist. + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, NOT_BLOCKLISTED); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); +} + +// 1. The extension is added to the Safe Browsing greylist with +// BLOCKLISTED_CWS_POLICY_VIOLATION state. +// 2. User re-enabled the extension. +// 3. The extension is added to the Omaha attribute greylist with +// _policy_violation attribute. +// 4. The extension is removed from the Safe Browsing greylist. +// 5. The extension is removed from the Omaha attribute greylist. +TEST_F( + BlocklistStatesInteractionUnitTest, + SafeBrowsingPolicyViolationThenOmahaAttributePolicyViolationWithUserAction) { + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, + BLOCKLISTED_CWS_POLICY_VIOLATION); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + EXPECT_TRUE(blocklist_prefs::HasAcknowledgedBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + extension_prefs())); + + // The extension is manually re-enabled. + service()->EnableExtension(kTestExtensionId); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + true); + // The extension is not disabled again, because it was previously manually + // re-enabled. + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(extension_prefs()->HasDisableReason( + kTestExtensionId, disable_reason::DISABLE_GREYLIST)); + + SetSafeBrowsingBlocklistStateForExtension(kTestExtensionId, NOT_BLOCKLISTED); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + // The acknowledged state should not be cleared yet, because it is still in + // the Omaha attribute greylist. + EXPECT_TRUE(blocklist_prefs::HasAcknowledgedBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + extension_prefs())); + + SetOmahaBlocklistStateForExtension(kTestExtensionId, "_policy_violation", + false); + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + // The acknowledged state should be removed now. + EXPECT_FALSE(blocklist_prefs::HasAcknowledgedBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + extension_prefs())); +} #endif } // namespace extensions
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc index 7aa8e3c..e56ca28 100644 --- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc +++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -24,10 +24,6 @@ #include "ppapi/buildflags/buildflags.h" #include "ui/base/resource/resource_bundle.h" -#if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/grit/pdf_resources_map.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/keyboard/ui/resources/keyboard_resource_util.h" #include "base/command_line.h" @@ -46,6 +42,7 @@ #if BUILDFLAG(ENABLE_PDF) #include <utility> #include "chrome/browser/pdf/pdf_extension_util.h" +#include "chrome/grit/pdf_resources_map.h" #endif // BUILDFLAG(ENABLE_PDF) namespace extensions { @@ -109,10 +106,6 @@ AddComponentResourceEntries(kExtraComponentExtensionResources, base::size(kExtraComponentExtensionResources)); -#if BUILDFLAG(ENABLE_PLUGINS) - AddComponentResourceEntries(kPdfResources, kPdfResourcesSize); -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) // Add Files app JS modules resources. AddComponentResourceEntries(kFileManagerResources, kFileManagerResourcesSize); @@ -136,6 +129,8 @@ #endif #if BUILDFLAG(ENABLE_PDF) + AddComponentResourceEntries(kPdfResources, kPdfResourcesSize); + // ResourceBundle is not always initialized in unit tests. if (ui::ResourceBundle::HasSharedInstance()) { base::Value dict(base::Value::Type::DICTIONARY);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 65c387c6..125d128 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -54,6 +54,7 @@ #include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h" #include "chrome/browser/extensions/install_verifier.h" #include "chrome/browser/extensions/installed_loader.h" +#include "chrome/browser/extensions/omaha_attributes_handler.h" #include "chrome/browser/extensions/pending_extension_manager.h" #include "chrome/browser/extensions/permissions_updater.h" #include "chrome/browser/extensions/shared_module_service.h" @@ -375,6 +376,7 @@ safe_browsing_verdict_handler_(extension_prefs, ExtensionRegistry::Get(profile), this), + omaha_attributes_handler_(extension_prefs, this), registry_(ExtensionRegistry::Get(profile)), pending_extension_manager_(profile), install_directory_(install_directory), @@ -842,17 +844,20 @@ const base::Value& attributes) { DCHECK_CURRENTLY_ON(BrowserThread::UI); HandleMalwareOmahaAttribute(extension_id, attributes); - omaha_attributes_handler_.PerformActionBasedOnOmahaAttributes(attributes); + omaha_attributes_handler_.PerformActionBasedOnOmahaAttributes(extension_id, + attributes); allowlist_.PerformActionBasedOnOmahaAttributes(extension_id, attributes); } void ExtensionService::HandleMalwareOmahaAttribute( const std::string& extension_id, const base::Value& attributes) { - const base::Value* malware_value = attributes.FindKey("_malware"); + bool has_malware_value = + OmahaAttributesHandler::HasOmahaBlocklistStateInAttributes( + attributes, BitMapBlocklistState::BLOCKLISTED_MALWARE); if (!base::FeatureList::IsEnabled( extensions_features::kDisableMalwareExtensionsRemotely) || - malware_value == nullptr || !malware_value->GetBool()) { + !has_malware_value) { OmahaAttributesHandler::ReportNoUpdateCheckKeys(); // Omaha attributes may have previously have the "_malware" key. MaybeEnableRemotelyDisabledExtension(extension_id);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index b123bc4..376fb41 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -552,6 +552,7 @@ bool CanBlockExtension(const Extension* extension) const; // Handles the malware Omaha attribute for remotely disabled extensions. + // TODO(crbug.com/1193695): Move this function to OmahaAttributesHandler. void HandleMalwareOmahaAttribute(const std::string& extension_id, const base::Value& attributes);
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 105512a3..9e44a6e 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -95,6 +95,8 @@ #include "components/prefs/scoped_user_pref_update.h" #include "components/safe_browsing/buildflags.h" #include "components/services/storage/public/mojom/indexed_db_control.mojom.h" +#include "components/services/storage/public/mojom/local_storage_control.mojom.h" +#include "components/services/storage/public/mojom/storage_usage_info.mojom.h" #include "components/sync/model/string_ordinal.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -159,6 +161,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" +#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" #include "url/origin.h" @@ -5100,18 +5103,25 @@ base::BindOnce(&CreateDatabase, base::Unretained(db_tracker), origin_id)); task_environment()->RunUntilIdle(); - // Create local storage. We only simulate this by creating the backing files. - // Note: This test depends on details of how the dom_storage library - // stores data in the host file system. - base::FilePath lso_dir_path = - profile()->GetPath().AppendASCII("Local Storage"); - base::FilePath lso_file_path = lso_dir_path.AppendASCII(origin_id) - .AddExtension(FILE_PATH_LITERAL(".localstorage")); - EXPECT_TRUE(base::CreateDirectory(lso_dir_path)); - EXPECT_EQ(0, base::WriteFile(lso_file_path, nullptr, 0)); - EXPECT_TRUE(base::PathExists(lso_file_path)); + // Create local storage. + auto* local_storage_control = + profile()->GetDefaultStoragePartition()->GetLocalStorageControl(); + mojo::Remote<blink::mojom::StorageArea> area; + local_storage_control->BindStorageArea(url::Origin::Create(ext_url), + area.BindNewPipeAndPassReceiver()); + { + bool success = false; + base::RunLoop run_loop; + area->Put({'k', 'e', 'y'}, {'v', 'a', 'l', 'u', 'e'}, absl::nullopt, + "source", base::BindLambdaForTesting([&](bool success_in) { + success = success_in; + run_loop.Quit(); + })); + run_loop.Run(); + ASSERT_TRUE(success); + } - // Create indexed db. Similarly, it is enough to only simulate this by + // Create indexed db. It is enough to only simulate this by // creating the directory on the disk, and resetting the caches of // "known" origins. auto& idb_control = @@ -5161,8 +5171,18 @@ base::Unretained(db_tracker))); task_environment()->RunUntilIdle(); - // Check that the LSO file has been removed. - EXPECT_FALSE(base::PathExists(lso_file_path)); + // Check that the localStorage data been removed. + std::vector<storage::mojom::StorageUsageInfoPtr> usage_infos; + { + base::RunLoop run_loop; + local_storage_control->GetUsage(base::BindLambdaForTesting( + [&](std::vector<storage::mojom::StorageUsageInfoPtr> usage_infos_in) { + usage_infos.swap(usage_infos_in); + run_loop.Quit(); + })); + run_loop.Run(); + } + EXPECT_TRUE(usage_infos.empty()); // Check if the indexed db has disappeared too. EXPECT_FALSE(base::DirectoryExists(idb_path)); @@ -5258,18 +5278,25 @@ base::BindOnce(&CreateDatabase, base::Unretained(db_tracker), origin_id)); task_environment()->RunUntilIdle(); - // Create local storage. We only simulate this by creating the backing files. - // Note: This test depends on details of how the dom_storage library - // stores data in the host file system. - base::FilePath lso_dir_path = - profile()->GetPath().AppendASCII("Local Storage"); - base::FilePath lso_file_path = lso_dir_path.AppendASCII(origin_id) - .AddExtension(FILE_PATH_LITERAL(".localstorage")); - EXPECT_TRUE(base::CreateDirectory(lso_dir_path)); - EXPECT_EQ(0, base::WriteFile(lso_file_path, nullptr, 0)); - EXPECT_TRUE(base::PathExists(lso_file_path)); + // Create local storage. + auto* local_storage_control = + profile()->GetDefaultStoragePartition()->GetLocalStorageControl(); + mojo::Remote<blink::mojom::StorageArea> area; + local_storage_control->BindStorageArea(url::Origin::Create(origin1), + area.BindNewPipeAndPassReceiver()); + { + bool success = false; + base::RunLoop run_loop; + area->Put({'k', 'e', 'y'}, {'v', 'a', 'l', 'u', 'e'}, absl::nullopt, + "source", base::BindLambdaForTesting([&](bool success_in) { + success = success_in; + run_loop.Quit(); + })); + run_loop.Run(); + ASSERT_TRUE(success); + } - // Create indexed db. Similarly, it is enough to only simulate this by + // Create indexed db. It is enough to only simulate this by // creating the directory on the disk, and resetting the caches of // "known" origins. auto& idb_control = @@ -5341,8 +5368,18 @@ base::Unretained(db_tracker))); task_environment()->RunUntilIdle(); - // Check that the LSO file has been removed. - EXPECT_FALSE(base::PathExists(lso_file_path)); + // Check that the localStorage data been removed. + std::vector<storage::mojom::StorageUsageInfoPtr> usage_infos; + { + base::RunLoop run_loop; + local_storage_control->GetUsage(base::BindLambdaForTesting( + [&](std::vector<storage::mojom::StorageUsageInfoPtr> usage_infos_in) { + usage_infos.swap(usage_infos_in); + run_loop.Quit(); + })); + run_loop.Run(); + } + EXPECT_TRUE(usage_infos.empty()); // Check if the indexed db has disappeared too. EXPECT_FALSE(base::DirectoryExists(idb_path));
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc index 6f763d64..86b9e3e4f 100644 --- a/chrome/browser/extensions/extension_tabs_apitest.cc +++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -75,107 +75,92 @@ browser()->profile()->GetPrefs()->SetBoolean( prefs::kHomePageIsNewTabPage, true); - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "crud.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "crud.html"})) << message_; } // TODO(crbug.com/1177118) Re-enable test IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, DISABLED_TabAudible) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "audible.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "audible.html"})) << message_; } // http://crbug.com/521410 IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, DISABLED_TabMuted) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "muted.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "muted.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, Tabs2) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "crud2.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "crud2.html"})) << message_; } // crbug.com/149924 IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, DISABLED_TabDuplicate) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "duplicate.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "duplicate.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabSize) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "tab_size.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "tab_size.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabUpdate) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "update.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "update.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabPinned) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "pinned.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "pinned.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabMove) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "move.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "move.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabEvents) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "events.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "events.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabRelativeURLs) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/basics", .page_url = "relative_urls.html"})) + ASSERT_TRUE( + RunExtensionTest("tabs/basics", {.page_url = "relative_urls.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabQuery) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "query.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "query.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabHighlight) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "highlight.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "highlight.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabCrashBrowser) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "crash.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "crash.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabOpener) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "opener.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "opener.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabRemove) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "remove.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "remove.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabRemoveMultiple) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/basics", .page_url = "remove-multiple.html"})) + ASSERT_TRUE( + RunExtensionTest("tabs/basics", {.page_url = "remove-multiple.html"})) << message_; } @@ -208,22 +193,22 @@ }; IN_PROC_BROWSER_TEST_F(ExtensionApiCaptureTest, CaptureVisibleTabJpeg) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/capture_visible_tab", .page_url = "test_jpeg.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab", + {.page_url = "test_jpeg.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiCaptureTest, CaptureVisibleTabPng) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/capture_visible_tab", .page_url = "test_png.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab", + {.page_url = "test_png.html"})) << message_; } // TODO(crbug.com/1177118) Re-enable test IN_PROC_BROWSER_TEST_F(ExtensionApiCaptureTest, DISABLED_CaptureVisibleTabRace) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/capture_visible_tab", .page_url = "test_race.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab", + {.page_url = "test_race.html"})) << message_; } @@ -234,17 +219,17 @@ #define MAYBE_CaptureVisibleFile CaptureVisibleFile #endif IN_PROC_BROWSER_TEST_F(ExtensionApiCaptureTest, MAYBE_CaptureVisibleFile) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/capture_visible_tab", .page_url = "test_file.html"}, - {.allow_file_access = true})) + ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab", + {.page_url = "test_file.html"}, + {.allow_file_access = true})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiCaptureTest, CaptureVisibleDisabled) { browser()->profile()->GetPrefs()->SetBoolean(prefs::kDisableScreenshots, true); - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/capture_visible_tab", .page_url = "test_disabled.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab", + {.page_url = "test_disabled.html"})) << message_; } @@ -326,20 +311,19 @@ } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, GetViewsOfCreatedPopup) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/basics", .page_url = "get_views_popup.html"})) + ASSERT_TRUE( + RunExtensionTest("tabs/basics", {.page_url = "get_views_popup.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, GetViewsOfCreatedWindow) { - ASSERT_TRUE(RunExtensionTest( - {.name = "tabs/basics", .page_url = "get_views_window.html"})) + ASSERT_TRUE( + RunExtensionTest("tabs/basics", {.page_url = "get_views_window.html"})) << message_; } IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, OnUpdatedDiscardedState) { - ASSERT_TRUE( - RunExtensionTest({.name = "tabs/basics", .page_url = "discarded.html"})) + ASSERT_TRUE(RunExtensionTest("tabs/basics", {.page_url = "discarded.html"})) << message_; } @@ -360,10 +344,9 @@ is_incognito_enabled ? "true" : "false", extensions::ExtensionTabUtil::GetWindowId(incognito_browser)); - EXPECT_TRUE(RunExtensionTest({.name = "tabs/basics", - .page_url = "incognito.html", - .custom_arg = args.c_str()}, - {.allow_in_incognito = is_incognito_enabled})) + EXPECT_TRUE(RunExtensionTest( + "tabs/basics", {.page_url = "incognito.html", .custom_arg = args.c_str()}, + {.allow_in_incognito = is_incognito_enabled})) << message_; }
diff --git a/chrome/browser/extensions/omaha_attributes_handler.cc b/chrome/browser/extensions/omaha_attributes_handler.cc index 1c1191d..700ed79 100644 --- a/chrome/browser/extensions/omaha_attributes_handler.cc +++ b/chrome/browser/extensions/omaha_attributes_handler.cc
@@ -6,7 +6,11 @@ #include "base/metrics/histogram_functions.h" #include "base/values.h" +#include "chrome/browser/extensions/blocklist_extension_prefs.h" +#include "chrome/browser/extensions/extension_service.h" #include "content/public/browser/browser_thread.h" +#include "extensions/browser/blocklist_state.h" +#include "extensions/common/extension_features.h" namespace extensions { @@ -35,27 +39,85 @@ base::UmaHistogramCounts100("Extensions.ExtensionReenabledRemotely", 1); } +// static +bool OmahaAttributesHandler::HasOmahaBlocklistStateInAttributes( + const base::Value& attributes, + BitMapBlocklistState state) { + const base::Value* state_value = nullptr; + switch (state) { + case BitMapBlocklistState::BLOCKLISTED_MALWARE: + state_value = attributes.FindKey("_malware"); + break; + case BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION: + state_value = attributes.FindKey("_policy_violation"); + break; + case BitMapBlocklistState::BLOCKLISTED_POTENTIALLY_UNWANTED: + state_value = attributes.FindKey("_potentially_uws"); + break; + case BitMapBlocklistState::NOT_BLOCKLISTED: + case BitMapBlocklistState::BLOCKLISTED_SECURITY_VULNERABILITY: + NOTREACHED() + << "The other states are not applicable in Omaha attributes."; + state_value = nullptr; + break; + } + return state_value && state_value->GetBool(); +} + +OmahaAttributesHandler::OmahaAttributesHandler( + ExtensionPrefs* extension_prefs, + ExtensionService* extension_service) + : extension_prefs_(extension_prefs), + extension_service_(extension_service) {} + void OmahaAttributesHandler::PerformActionBasedOnOmahaAttributes( + const ExtensionId& extension_id, const base::Value& attributes) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); ReportPolicyViolationUWSOmahaAttributes(attributes); - // TODO(crbug.com/1180996): Perform action based on the attributes. + HandleGreylistOmahaAttribute( + extension_id, attributes, + extensions_features::kDisablePolicyViolationExtensionsRemotely, + BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION); } void OmahaAttributesHandler::ReportPolicyViolationUWSOmahaAttributes( const base::Value& attributes) { - const base::Value* uws_value = attributes.FindKey("_potentially_uws"); - if (uws_value != nullptr && uws_value->GetBool()) { + bool has_uws_value = HasOmahaBlocklistStateInAttributes( + attributes, BitMapBlocklistState::BLOCKLISTED_POTENTIALLY_UNWANTED); + if (has_uws_value) { ReportExtensionDisabledRemotely( /*should_be_remotely_disabled=*/false, ExtensionUpdateCheckDataKey::kPotentiallyUWS); } - const base::Value* pv_value = attributes.FindKey("_policy_violation"); - if (pv_value != nullptr && pv_value->GetBool()) { + bool has_pv_value = HasOmahaBlocklistStateInAttributes( + attributes, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION); + if (has_pv_value) { ReportExtensionDisabledRemotely( /*should_be_remotely_disabled=*/false, ExtensionUpdateCheckDataKey::kPolicyViolation); } } +void OmahaAttributesHandler::HandleGreylistOmahaAttribute( + const ExtensionId& extension_id, + const base::Value& attributes, + const base::Feature& feature_flag, + BitMapBlocklistState greylist_state) { + bool has_attribute_value = + HasOmahaBlocklistStateInAttributes(attributes, greylist_state); + if (!base::FeatureList::IsEnabled(feature_flag) || !has_attribute_value) { + blocklist_prefs::RemoveOmahaBlocklistState(extension_id, greylist_state, + extension_prefs_); + extension_service_->ClearGreylistedAcknowledgedStateAndMaybeReenable( + extension_id); + return; + } + + blocklist_prefs::AddOmahaBlocklistState(extension_id, greylist_state, + extension_prefs_); + extension_service_->MaybeDisableGreylistedExtension(extension_id, + greylist_state); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/omaha_attributes_handler.h b/chrome/browser/extensions/omaha_attributes_handler.h index 3e311fb..01c06c0 100644 --- a/chrome/browser/extensions/omaha_attributes_handler.h +++ b/chrome/browser/extensions/omaha_attributes_handler.h
@@ -5,11 +5,17 @@ #ifndef CHROME_BROWSER_EXTENSIONS_OMAHA_ATTRIBUTES_HANDLER_H_ #define CHROME_BROWSER_EXTENSIONS_OMAHA_ATTRIBUTES_HANDLER_H_ +#include "chrome/browser/extensions/blocklist.h" +#include "extensions/browser/blocklist_state.h" +#include "extensions/common/extension_id.h" + namespace base { class Value; } namespace extensions { +class ExtensionPrefs; +class ExtensionService; // These values are logged to UMA. Entries should not be renumbered and // numeric values should never be reused. Please keep in sync with @@ -32,7 +38,8 @@ // Manages the Omaha attributes blocklist/greylist states in extension pref. class OmahaAttributesHandler { public: - OmahaAttributesHandler() = default; + OmahaAttributesHandler(ExtensionPrefs* extension_prefs, + ExtensionService* extension_service); OmahaAttributesHandler(const OmahaAttributesHandler&) = delete; OmahaAttributesHandler& operator=(const OmahaAttributesHandler&) = delete; ~OmahaAttributesHandler() = default; @@ -48,13 +55,30 @@ // Logs UMA metrics when a remotely disabled extension is re-enabled. static void ReportReenableExtensionFromMalware(); + // Checks whether the `state` is in the `attributes`. + static bool HasOmahaBlocklistStateInAttributes(const base::Value& attributes, + BitMapBlocklistState state); + // Performs action based on Omaha attributes for the extension. // TODO(crbug.com/1193695): This function currently only handles greylist // states. We should move blocklist handling into this class too. - void PerformActionBasedOnOmahaAttributes(const base::Value& attributes); + void PerformActionBasedOnOmahaAttributes(const ExtensionId& extension_id, + const base::Value& attributes); private: void ReportPolicyViolationUWSOmahaAttributes(const base::Value& attributes); + + // Performs action based on `attributes` for the `extension_id`. If the + // extension is not in the `greylist_state` or the `feature_flag` is disabled, + // remove it from the Omaha blocklist state and maybe re-enable it. Otherwise, + // add it to the Omaha blocklist state and maybe disable it. + void HandleGreylistOmahaAttribute(const ExtensionId& extension_id, + const base::Value& attributes, + const base::Feature& feature_flag, + BitMapBlocklistState greylist_state); + + ExtensionPrefs* extension_prefs_ = nullptr; + ExtensionService* extension_service_ = nullptr; }; } // namespace extensions
diff --git a/chrome/browser/extensions/omaha_attributes_handler_unittest.cc b/chrome/browser/extensions/omaha_attributes_handler_unittest.cc index b66d747e..3430657 100644 --- a/chrome/browser/extensions/omaha_attributes_handler_unittest.cc +++ b/chrome/browser/extensions/omaha_attributes_handler_unittest.cc
@@ -5,9 +5,13 @@ #include "chrome/browser/extensions/omaha_attributes_handler.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/values.h" +#include "chrome/browser/extensions/blocklist_extension_prefs.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/common/extension_features.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions { @@ -20,13 +24,19 @@ } // namespace // Test suite to test Omaha attribute handler. -using OmahaAttributesHandlerUnitTest = ExtensionServiceTestBase; +class OmahaAttributesHandlerUnitTest : public ExtensionServiceTestBase { + public: + OmahaAttributesHandlerUnitTest() { + feature_list_.InitAndEnableFeature( + extensions_features::kDisablePolicyViolationExtensionsRemotely); + } +}; TEST_F(OmahaAttributesHandlerUnitTest, LogPolicyViolationUWSMetrics) { base::HistogramTester histograms; base::Value attributes(base::Value::Type::DICTIONARY); - attributes.SetKey("_potentially_uws", base::Value(true)); - attributes.SetKey("_policy_violation", base::Value(true)); + attributes.SetBoolKey("_policy_violation", true); + attributes.SetBoolKey("_potentially_uws", true); InitializeEmptyExtensionService(); service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); @@ -41,4 +51,110 @@ /* expected_count */ 1); } +TEST_F(OmahaAttributesHandlerUnitTest, DisableRemotelyForPolicyViolation) { + InitializeGoodInstalledExtensionService(); + service()->Init(); + + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + const ExtensionSet& disabled_extensions = registry()->disabled_extensions(); + + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + + base::Value attributes(base::Value::Type::DICTIONARY); + attributes.SetBoolKey("_policy_violation", true); + service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); + + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(disabled_extensions.Contains(kTestExtensionId)); + + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); + EXPECT_TRUE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + prefs)); + EXPECT_EQ(disable_reason::DISABLE_GREYLIST, + prefs->GetDisableReasons(kTestExtensionId)); + + // Remove extensions from greylist. + attributes.SetBoolKey("_policy_violation", false); + service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); + EXPECT_FALSE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + ExtensionPrefs::Get(profile()))); + EXPECT_EQ(disable_reason::DISABLE_NONE, + prefs->GetDisableReasons(kTestExtensionId)); + + EXPECT_FALSE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + prefs)); + + // The extension is re-enabled. + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(disabled_extensions.Contains(kTestExtensionId)); +} + +TEST_F(OmahaAttributesHandlerUnitTest, KeepDisabledWhenMalwareRemoved) { + InitializeGoodInstalledExtensionService(); + service()->Init(); + + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + const ExtensionSet& blocklisted_extensions = + registry()->blocklisted_extensions(); + + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); + + base::Value attributes(base::Value::Type::DICTIONARY); + attributes.SetBoolKey("_malware", true); + attributes.SetBoolKey("_policy_violation", true); + service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); + + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_TRUE(blocklisted_extensions.Contains(kTestExtensionId)); + EXPECT_EQ(disable_reason::DISABLE_REMOTELY_FOR_MALWARE | + disable_reason::DISABLE_GREYLIST, + prefs->GetDisableReasons(kTestExtensionId)); + + // Remove malware. + attributes.SetBoolKey("_malware", false); + service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); + + // The extension is not enabled because the policy violation bit is not + // cleared. + EXPECT_FALSE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(blocklisted_extensions.Contains(kTestExtensionId)); + EXPECT_EQ(disable_reason::DISABLE_GREYLIST, + prefs->GetDisableReasons(kTestExtensionId)); +} + +// Test suite to test Omaha attribute handler when features are disabled. +class OmahaAttributesHandlerWithFeatureDisabledUnitTest + : public ExtensionServiceTestBase { + public: + OmahaAttributesHandlerWithFeatureDisabledUnitTest() { + feature_list_.InitAndDisableFeature( + extensions_features::kDisablePolicyViolationExtensionsRemotely); + } +}; + +TEST_F(OmahaAttributesHandlerWithFeatureDisabledUnitTest, + DoNotDisableRemotelyWhenPolicyViolationFlagDisabled) { + InitializeGoodInstalledExtensionService(); + service()->Init(); + + const ExtensionSet& enabled_extensions = registry()->enabled_extensions(); + const ExtensionSet& disabled_extensions = registry()->disabled_extensions(); + + base::Value attributes(base::Value::Type::DICTIONARY); + attributes.SetBoolKey("_policy_violation", true); + service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); + + // Since the flag is disabled, we don't expect the extension to be affected. + EXPECT_TRUE(enabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(disabled_extensions.Contains(kTestExtensionId)); + EXPECT_FALSE(blocklist_prefs::HasOmahaBlocklistState( + kTestExtensionId, BitMapBlocklistState::BLOCKLISTED_CWS_POLICY_VIOLATION, + ExtensionPrefs::Get(profile()))); +} + } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index c74f3e07..c72f054 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1723,12 +1723,12 @@ { "name": "enable-experimental-accessibility-language-detection", "owners": [ "chrishall", "//ui/accessibility/OWNERS" ], - "expiry_milestone": 91 + "expiry_milestone": 98 }, { "name": "enable-experimental-accessibility-language-detection-dynamic", "owners": [ "chrishall", "//ui/accessibility/OWNERS" ], - "expiry_milestone": 91 + "expiry_milestone": 98 }, { "name": "enable-experimental-accessibility-switch-access-setup-guide", @@ -2996,7 +2996,7 @@ { "name": "forced-colors", "owners": [ "almaher@microsoft.com" ], - "expiry_milestone": 92 + "expiry_milestone": 95 }, { "name": "form-controls-dark-mode",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 60c5a96..359f0dc 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3185,10 +3185,6 @@ "Enable a history sub page to the page info menu, and a button to forget " "a site, removing all preferences and history."; -const char kPageInfoV2Name[] = "Page info version two"; -const char kPageInfoV2Description[] = - "Enable the second version of the page info menu."; - extern const char kPageInfoV2DesktopName[]; extern const char kPageInfoV2DesktopDescription[];
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 9f38272..e203545 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1844,9 +1844,6 @@ extern const char kPageInfoHistoryName[]; extern const char kPageInfoHistoryDescription[]; -extern const char kPageInfoV2Name[]; -extern const char kPageInfoV2Description[]; - extern const char kPhotoPickerVideoSupportName[]; extern const char kPhotoPickerVideoSupportDescription[];
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc index a4fb98e..c7a4fc5 100644 --- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc +++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
@@ -421,7 +421,7 @@ &reputation::IsTargetHostAllowlistedBySafetyTipsComponent, proto); std::string matched_domain; if (GetMatchingDomain(navigated_domain, engaged_sites, in_target_allowlist, - &matched_domain, match_type)) { + proto, &matched_domain, match_type)) { DCHECK(!matched_domain.empty()); // matched_domain can be a top domain or an engaged domain. Simply use its
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc index 0edfd1bc..45787c3 100644 --- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc +++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -578,7 +578,7 @@ TargetEmbedding_EmbedderAllowlist) { const GURL kNavigatedUrl = GetURL("google.com.allowlisted.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - reputation::SetSafetyTipAllowlistPatterns({"allowlisted.com/"}, {}); + reputation::SetSafetyTipAllowlistPatterns({"allowlisted.com/"}, {}, {}); TestInterstitialNotShown(browser(), kNavigatedUrl); CheckNoUkm(); } @@ -588,7 +588,17 @@ TargetEmbedding_TargetAllowlist) { const GURL kNavigatedUrl = GetURL("foo.scholar.google.com.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - reputation::SetSafetyTipAllowlistPatterns({}, {"scholar\\.google\\.com"}); + reputation::SetSafetyTipAllowlistPatterns({}, {"scholar\\.google\\.com"}, {}); + TestInterstitialNotShown(browser(), kNavigatedUrl); + CheckNoUkm(); +} + +// Target embedding shouldn't trigger on component-delivered common words. +IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationThrottleBrowserTest, + TargetEmbedding_ComponentCommonWords) { + const GURL kNavigatedUrl = GetURL("google.com.example.com"); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + reputation::SetSafetyTipAllowlistPatterns({}, {}, {"google"}); TestInterstitialNotShown(browser(), kNavigatedUrl); CheckNoUkm(); } @@ -599,7 +609,7 @@ TargetEmbedding_TargetAllowlistWithNoSeparators) { const GURL kNavigatedUrl = GetURL("googlecom.example.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}); + reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}, {}); TestInterstitialNotShown(browser(), kNavigatedUrl); CheckNoUkm(); } @@ -781,7 +791,7 @@ IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationThrottleBrowserTest, EditDistance_TopDomain_Target_Allowlist) { base::HistogramTester histograms; - reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}); + reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}, {}); // The skeleton of this domain, gooogle.corn, is one 1 edit away from // google.corn, the skeleton of google.com. @@ -802,7 +812,7 @@ EditDistance_EngagedDomain_Target_Allowlist) { base::HistogramTester histograms; SetEngagementScore(browser(), GURL("https://test-site.com"), kHighEngagement); - reputation::SetSafetyTipAllowlistPatterns({}, {"test-site\\.com"}); + reputation::SetSafetyTipAllowlistPatterns({}, {"test-site\\.com"}, {}); // The skeleton of this domain is one 1 edit away from the skeleton of // test-site.com. @@ -989,7 +999,7 @@ reputation::SetSafetyTipAllowlistPatterns( {"xn--googl-fsa.com/", // googlé.com in punycode "site.test/", "another-site.test/"}, - {}); + {}, {}); TestInterstitialNotShown(browser(), GetURL("googlé.com")); CheckNoUkm();
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc index 4f58382..37aef84 100644 --- a/chrome/browser/media/cast_mirroring_service_host.cc +++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" #include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/service_sandbox_type.h" #include "components/mirroring/browser/single_client_video_capture_host.h" #include "components/mirroring/mojom/cast_message_channel.mojom.h" #include "components/mirroring/mojom/session_observer.mojom.h"
diff --git a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc index 10b104ad..f30bc7ff 100644 --- a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc +++ b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc
@@ -19,6 +19,7 @@ #include "media/audio/audio_device_description.h" #include "media/mojo/mojom/capture_handle.mojom.h" #include "media/mojo/mojom/display_media_information.mojom.h" +#include "third_party/blink/public/mojom/media/capture_handle_config.mojom.h" #include "ui/base/l10n/l10n_util.h" namespace {
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc index d4075ccf..020e43c 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -13,6 +13,7 @@ #include "base/files/file.h" #include "base/hash/hash.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/numerics/checked_math.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" @@ -262,7 +263,8 @@ std::unique_ptr<NearbyConnectionsManager> nearby_connections_manager, chromeos::nearby::NearbyProcessManager* process_manager, std::unique_ptr<PowerClient> power_client) - : profile_(profile), + : prefs_(prefs), + profile_(profile), nearby_connections_manager_(std::move(nearby_connections_manager)), process_manager_(process_manager), power_client_(std::move(power_client)), @@ -300,7 +302,7 @@ DCHECK(nearby_connections_manager_); DCHECK(power_client_); - RecordNearbyShareEnabledMetric(prefs); + RecordNearbyShareEnabledMetric(prefs_); auto* session_controller = ash::SessionController::Get(); if (session_controller) { @@ -1140,6 +1142,8 @@ void NearbySharingServiceImpl::OnEnabledChanged(bool enabled) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + RecordNearbyShareEnabledMetric(prefs_); + base::UmaHistogramBoolean("Nearby.Share.EnabledStateChanged", enabled); if (enabled) { NS_LOG(VERBOSE) << __func__ << ": Nearby sharing enabled!"; local_device_data_manager_->Start();
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h index 3b4a19c..7d22ba38 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -392,6 +392,7 @@ void AbortAndCloseConnectionIfNecessary(const TransferMetadata::Status status, const ShareTarget& share_target); + PrefService* prefs_ = nullptr; Profile* profile_; std::unique_ptr<NearbyConnectionsManager> nearby_connections_manager_; chromeos::nearby::NearbyProcessManager* process_manager_;
diff --git a/chrome/browser/notifications/notifier_state_tracker.cc b/chrome/browser/notifications/notifier_state_tracker.cc index 8916238..5529e0d1e 100644 --- a/chrome/browser/notifications/notifier_state_tracker.cc +++ b/chrome/browser/notifications/notifier_state_tracker.cc
@@ -180,8 +180,9 @@ extensions::api::notifications::PermissionLevel permission = enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED : extensions::api::notifications::PERMISSION_LEVEL_DENIED; - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->AppendString(extensions::api::notifications::ToString(permission)); + std::vector<base::Value> args; + args.push_back( + base::Value(extensions::api::notifications::ToString(permission))); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events::NOTIFICATIONS_ON_PERMISSION_LEVEL_CHANGED, extensions::api::notifications::OnPermissionLevelChanged::kEventName,
diff --git a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.cc index 712821e5..a3334cf5 100644 --- a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.cc
@@ -94,10 +94,6 @@ return STOP_OBSERVING; after_srp_metrics_ = tab_helper->after_srp_metrics(); - data_saver_enabled_at_commit_ = data_reduction_proxy:: - DataReductionProxySettings::IsDataSaverEnabledByUser( - profile->IsOffTheRecord(), profile->GetPrefs()); - history::HistoryService* history_service = HistoryServiceFactory::GetForProfileIfExists( profile, ServiceAccessType::IMPLICIT_ACCESS); @@ -229,10 +225,6 @@ "PageLoad.Clients.SubresourceLoading.LoadedCSSJSBeforeFCP.Noncached", loaded_css_js_from_network_before_fcp_); - // Only record UKM for Data Saver users. - if (!data_saver_enabled_at_commit_) - return; - RecordPrefetchProxyEvent(); RecordAfterSRPEvent(); }
diff --git a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.h index 19b2f54..7823511 100644 --- a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer.h
@@ -73,9 +73,6 @@ resources) override; void OnEventOccurred(page_load_metrics::PageLoadMetricsEvent event) override; - // Whether data saver was enabled for this page load when it committed. - bool data_saver_enabled_at_commit_ = false; - // The time that the navigation started. Used to timebox the history service // query on commit. base::Time navigation_start_;
diff --git a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_browsertest.cc index 819aa68..7f63e52 100644 --- a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_browsertest.cc
@@ -26,16 +26,11 @@ #include "services/metrics/public/cpp/ukm_source.h" #include "testing/gtest/include/gtest/gtest.h" -class IsolatedPrerenderPageLoadMetricsObserverBrowserTest +class PrefetchProxyPageLoadMetricsObserverBrowserTest : public InProcessBrowserTest { public: - IsolatedPrerenderPageLoadMetricsObserverBrowserTest() = default; - ~IsolatedPrerenderPageLoadMetricsObserverBrowserTest() override = default; - - void EnableDataSaver() { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - data_reduction_proxy::switches::kEnableDataReductionProxy); - } + PrefetchProxyPageLoadMetricsObserverBrowserTest() = default; + ~PrefetchProxyPageLoadMetricsObserverBrowserTest() override = default; void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); @@ -100,7 +95,7 @@ std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_; }; -IN_PROC_BROWSER_TEST_F(IsolatedPrerenderPageLoadMetricsObserverBrowserTest, +IN_PROC_BROWSER_TEST_F(PrefetchProxyPageLoadMetricsObserverBrowserTest, BeforeFCPPlumbing) { base::HistogramTester histogram_tester; NavigateToOriginPath("/index.html"); @@ -117,7 +112,7 @@ #else #define MAYBE_HistoryPlumbing HistoryPlumbing #endif -IN_PROC_BROWSER_TEST_F(IsolatedPrerenderPageLoadMetricsObserverBrowserTest, +IN_PROC_BROWSER_TEST_F(PrefetchProxyPageLoadMetricsObserverBrowserTest, MAYBE_HistoryPlumbing) { base::HistogramTester histogram_tester; NavigateToOriginPath("/index.html"); @@ -139,9 +134,8 @@ "PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin", 0, 1); } -IN_PROC_BROWSER_TEST_F(IsolatedPrerenderPageLoadMetricsObserverBrowserTest, +IN_PROC_BROWSER_TEST_F(PrefetchProxyPageLoadMetricsObserverBrowserTest, RecordNothingOnUntrackedPage) { - EnableDataSaver(); base::HistogramTester histogram_tester; NavigateAway();
diff --git a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_unittest.cc index 878314b..ce993607 100644 --- a/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/prefetch_proxy_page_load_metrics_observer_unittest.cc
@@ -54,14 +54,9 @@ void set_navigation_url(const GURL& url) { navigation_url_ = url; } void set_in_main_frame(bool in_main_frame) { in_main_frame_ = in_main_frame; } - void StartTest(bool data_saver_enabled) { + void StartTest() { ResetTest(); - if (data_saver_enabled) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - data_reduction_proxy::switches::kEnableDataReductionProxy); - } - NavigateAndCommit(navigation_url_); tester()->SimulateTimingUpdate(timing_); } @@ -163,7 +158,7 @@ }; TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_CSS) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateCSSResource(true /* was_cached */, @@ -198,7 +193,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_JS) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateJSResource(true /* was_cached */, @@ -233,7 +228,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_Other) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateOtherResource(true /* was_cached */, @@ -268,7 +263,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_NotComplete) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateCSSResource(true /* was_cached */, @@ -303,7 +298,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_Subframe) { - StartTest(true /* data_saver_enabled */); + StartTest(); set_in_main_frame(false); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; @@ -339,7 +334,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, AfterFCP) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateCSSResource(true /* was_cached */, @@ -374,7 +369,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_MaxUKM) { - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateCSSResource(true /* was_cached */, @@ -425,33 +420,10 @@ VerifyUKMEntry(UkmEntry::kcount_css_js_loaded_cache_before_fcpName, 10); } -TEST_F(PrefetchProxyPageLoadMetricsObserverTest, BeforeFCP_NoUKM) { - StartTest(false /* data_saver_enabled */); - - std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; - resources.push_back(CreateCSSResource(true /* was_cached */, - true /* is_complete */, - true /* completed_before_fcp */)); - resources.push_back(CreateCSSResource(true /* was_cached */, - true /* is_complete */, - true /* completed_before_fcp */)); - - tester()->SimulateResourceDataUseUpdate(resources); - tester()->NavigateToUntrackedUrl(); - - tester()->histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.SubresourceLoading.LoadedCSSJSBeforeFCP.Noncached", 0, - 1); - tester()->histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.SubresourceLoading.LoadedCSSJSBeforeFCP.Cached", 2, 1); - - VerifyNoUKM(); -} - TEST_F(PrefetchProxyPageLoadMetricsObserverTest, DontRecordForNonHttp) { set_navigation_url(GURL("chrome://version")); - StartTest(true /* data_saver_enabled */); + StartTest(); std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; resources.push_back(CreateCSSResource(true /* was_cached */, @@ -483,7 +455,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_None) { - StartTest(true /* data_saver_enabled */); + StartTest(); tester()->NavigateToUntrackedUrl(); @@ -497,7 +469,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_Fail) { - StartTest(true /* data_saver_enabled */); + StartTest(); plm_observer()->CallOnOriginLastVisitResult( {false /* success */, base::Time()}); tester()->NavigateToUntrackedUrl(); @@ -512,7 +484,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_NullTime) { - StartTest(true /* data_saver_enabled */); + StartTest(); plm_observer()->CallOnOriginLastVisitResult( {true /* success */, base::Time()}); tester()->NavigateToUntrackedUrl(); @@ -527,7 +499,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_Today) { - StartTest(true /* data_saver_enabled */); + StartTest(); plm_observer()->CallOnOriginLastVisitResult( {true /* success */, base::Time::Now()}); @@ -543,7 +515,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_Yesterday) { - StartTest(true /* data_saver_enabled */); + StartTest(); plm_observer()->CallOnOriginLastVisitResult( {true /* success */, base::Time::Now() - base::TimeDelta::FromDays(1)}); @@ -559,7 +531,7 @@ } TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_MaxUKM) { - StartTest(true /* data_saver_enabled */); + StartTest(); plm_observer()->CallOnOriginLastVisitResult( {true /* success */, base::Time::Now() - base::TimeDelta::FromDays(181)}); @@ -574,18 +546,3 @@ VerifyUKMEntry(UkmEntry::kdays_since_last_visit_to_originName, /*ukm::GetExponentialBucketMin(180,1.70)=*/119); } - -TEST_F(PrefetchProxyPageLoadMetricsObserverTest, LastVisitToHost_NoUKM) { - StartTest(false /* data_saver_enabled */); - plm_observer()->CallOnOriginLastVisitResult( - {true /* success */, base::Time::Now() - base::TimeDelta::FromDays(1)}); - - tester()->NavigateToUntrackedUrl(); - - tester()->histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.SubresourceLoading.HasPreviousVisitToOrigin", true, 1); - tester()->histogram_tester().ExpectUniqueSample( - "PageLoad.Clients.SubresourceLoading.DaysSinceLastVisitToOrigin", 1, 1); - - VerifyNoUKM(); -}
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index f2be95d3..533c23b7 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -31,7 +31,6 @@ #include "chrome/browser/policy/homepage_location_policy_handler.h" #include "chrome/browser/policy/javascript_policy_handler.h" #include "chrome/browser/policy/network_prediction_policy_handler.h" -#include "chrome/browser/policy/printing_restrictions_policy_handler.h" #include "chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler.h" #include "chrome/browser/profiles/force_safe_search_policy_handler.h" #include "chrome/browser/profiles/force_youtube_safety_mode_policy_handler.h" @@ -100,6 +99,7 @@ #include "extensions/buildflags/buildflags.h" #include "media/media_buildflags.h" #include "ppapi/buildflags/buildflags.h" +#include "printing/buildflags/buildflags.h" #if defined(OS_ANDROID) #include "chrome/browser/first_run/android/first_run_prefs.h" @@ -155,6 +155,10 @@ #include "extensions/common/manifest.h" #endif // BUILDFLAG(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_PRINTING) +#include "chrome/browser/policy/printing_restrictions_policy_handler.h" +#endif + #if BUILDFLAG(ENABLE_SPELLCHECK) #include "components/spellcheck/browser/pref_names.h" #endif // BUILDFLAG(ENABLE_SPELLCHECK) @@ -1513,12 +1517,6 @@ SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED)); handlers->AddHandler( std::make_unique<WebUsbAllowDevicesForUrlsPolicyHandler>(chrome_schema)); - handlers->AddHandler( - std::make_unique<PrintingAllowedBackgroundGraphicsModesPolicyHandler>()); - handlers->AddHandler( - std::make_unique<PrintingBackgroundGraphicsDefaultPolicyHandler>()); - handlers->AddHandler( - std::make_unique<PrintingPaperSizeDefaultPolicyHandler>()); handlers->AddHandler(std::make_unique<DeveloperToolsPolicyHandler>()); handlers->AddHandler(std::make_unique<FileSelectionDialogsPolicyHandler>()); handlers->AddHandler(std::make_unique<JavascriptPolicyHandler>()); @@ -2040,6 +2038,15 @@ #endif // BUILDFLAG(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_PRINTING) + handlers->AddHandler( + std::make_unique<PrintingAllowedBackgroundGraphicsModesPolicyHandler>()); + handlers->AddHandler( + std::make_unique<PrintingBackgroundGraphicsDefaultPolicyHandler>()); + handlers->AddHandler( + std::make_unique<PrintingPaperSizeDefaultPolicyHandler>()); +#endif + #if BUILDFLAG(ENABLE_SPELLCHECK) handlers->AddHandler(std::make_unique<SpellcheckLanguagePolicyHandler>()); handlers->AddHandler(
diff --git a/chrome/browser/printing/print_backend_browsertest.cc b/chrome/browser/printing/print_backend_browsertest.cc index 7e73a04da..de068b5 100644 --- a/chrome/browser/printing/print_backend_browsertest.cc +++ b/chrome/browser/printing/print_backend_browsertest.cc
@@ -70,7 +70,7 @@ // Initialize and load the backend service with some test print drivers. void LaunchService() { print_backend_service_ = PrintBackendServiceTestImpl::LaunchForTesting( - remote_, test_print_backend_); + remote_, test_print_backend_, /*sandboxed=*/true); } // Load the test backend with a default printer driver.
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc index daa52f3..b9b7a65 100644 --- a/chrome/browser/printing/print_backend_service_manager.cc +++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -7,12 +7,14 @@ #include <string> #include "base/containers/flat_map.h" -#include "base/no_destructor.h" +#include "base/containers/flat_set.h" +#include "base/logging.h" #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/service_sandbox_type.h" #include "chrome/grit/generated_resources.h" #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/service_process_host.h" #include "mojo/public/cpp/bindings/remote.h" @@ -24,18 +26,38 @@ constexpr base::TimeDelta kResetOnIdleTimeout = base::TimeDelta::FromSeconds(20); +PrintBackendServiceManager* g_print_backend_service_manager_singleton = nullptr; + } // namespace PrintBackendServiceManager::PrintBackendServiceManager() = default; PrintBackendServiceManager::~PrintBackendServiceManager() = default; +bool PrintBackendServiceManager::ShouldSandboxPrintBackendService() const { + return sandbox_service_; +} + const mojo::Remote<printing::mojom::PrintBackendService>& PrintBackendServiceManager::GetService(const std::string& locale, const std::string& printer_name) { - if (service_remote_for_test_) - return *service_remote_for_test_; + // Value of `sandbox_service_` will be referenced during the service launch + // by `ShouldSandboxPrintBackendService()` if the service is started via + // `content::ServiceProcessHost::Launch()`. + sandbox_service_ = !PrinterDriverRequiresElevatedPrivilege(printer_name); + if (sandboxed_service_remote_for_test_) { + // The presence of a sandboxed remote for testing signals a testing + // environment. If no unsandboxed test service was provided for fallback + // processing then use the sandboxed one for that as well. + if (!sandbox_service_ && unsandboxed_service_remote_for_test_) + return *unsandboxed_service_remote_for_test_; + + return *sandboxed_service_remote_for_test_; + } + + RemotesMap& remote = + sandbox_service_ ? sandbox_remotes_ : unsandboxed_remotes_; std::string remote_id; #if defined(OS_WIN) // Windows drivers are not thread safe. Use a process per driver to prevent @@ -43,16 +65,19 @@ // https://crbug.com/957242 remote_id = printer_name; #endif - auto iter = remotes_.find(remote_id); - if (iter == remotes_.end()) { + auto iter = remote.find(remote_id); + if (iter == remote.end()) { // First time for this `remote_id`. - auto result = remotes_.emplace( + auto result = remote.emplace( printer_name, mojo::Remote<printing::mojom::PrintBackendService>()); iter = result.first; } mojo::Remote<printing::mojom::PrintBackendService>& service = iter->second; if (!service) { + VLOG(1) << "Launching print backend " + << (sandbox_service_ ? "sandboxed" : "unsandboxed") << " for '" + << remote_id << "'"; content::ServiceProcessHost::Launch( service.BindNewPipeAndPassReceiver(), content::ServiceProcessHost::Options() @@ -82,15 +107,44 @@ return service; } +bool PrintBackendServiceManager::PrinterDriverRequiresElevatedPrivilege( + const std::string& printer_name) const { + return drivers_requiring_elevated_privilege_.contains(printer_name); +} + +void PrintBackendServiceManager::SetPrinterDriverRequiresElevatedPrivilege( + const std::string& printer_name) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + VLOG(1) << "Destination '" << printer_name + << "' requires elevated privileges."; + drivers_requiring_elevated_privilege_.emplace(printer_name); +} + void PrintBackendServiceManager::SetServiceForTesting( mojo::Remote<printing::mojom::PrintBackendService>* remote) { - service_remote_for_test_ = remote; + sandboxed_service_remote_for_test_ = remote; +} + +void PrintBackendServiceManager::SetServiceForFallbackTesting( + mojo::Remote<printing::mojom::PrintBackendService>* remote) { + unsandboxed_service_remote_for_test_ = remote; } // static PrintBackendServiceManager& PrintBackendServiceManager::GetInstance() { - static base::NoDestructor<PrintBackendServiceManager> singleton; - return *singleton; + if (!g_print_backend_service_manager_singleton) { + g_print_backend_service_manager_singleton = + new PrintBackendServiceManager(); + } + return *g_print_backend_service_manager_singleton; +} + +// static +void PrintBackendServiceManager::ResetForTesting() { + if (g_print_backend_service_manager_singleton) { + delete g_print_backend_service_manager_singleton; + g_print_backend_service_manager_singleton = nullptr; + } } } // namespace printing
diff --git a/chrome/browser/printing/print_backend_service_manager.h b/chrome/browser/printing/print_backend_service_manager.h index 7e3c80f..0b2bb110 100644 --- a/chrome/browser/printing/print_backend_service_manager.h +++ b/chrome/browser/printing/print_backend_service_manager.h
@@ -8,6 +8,7 @@ #include <string> #include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "base/no_destructor.h" #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h" #include "mojo/public/cpp/bindings/remote.h" @@ -20,20 +21,43 @@ PrintBackendServiceManager& operator=(const PrintBackendServiceManager&) = delete; + // Returns true if the print backend service should be sandboxed, false + // otherwise. + bool ShouldSandboxPrintBackendService() const; + // Acquires a remote handle to the Print Backend Service instance, launching a // process to host the service if necessary. const mojo::Remote<printing::mojom::PrintBackendService>& GetService( const std::string& locale, const std::string& printer_name); + // Query if printer driver has been found to require elevated privilege in + // order to have print queries/commands succeed. + bool PrinterDriverRequiresElevatedPrivilege( + const std::string& printer_name) const; + + // Make note that `printer_name` has been detected as requiring elevated + // privileges in order to operate. + void SetPrinterDriverRequiresElevatedPrivilege( + const std::string& printer_name); + // Overrides the print backend service for testing. Caller retains ownership // of `remote`. void SetServiceForTesting( mojo::Remote<printing::mojom::PrintBackendService>* remote); + // Overrides the print backend service for testing when an alternate service + // is required for fallback processing after an access denied error. Caller + // retains ownership of `remote`. + void SetServiceForFallbackTesting( + mojo::Remote<printing::mojom::PrintBackendService>* remote); + // There is to be at most one instance of this at a time. static PrintBackendServiceManager& GetInstance(); + // Test support to revert to a fresh instance. + static void ResetForTesting(); + private: friend base::NoDestructor<PrintBackendServiceManager>; @@ -44,11 +68,25 @@ base::flat_map<std::string, mojo::Remote<printing::mojom::PrintBackendService>>; - RemotesMap remotes_; + // Keep separate mapping of remotes for sandboxed vs. unsandboxed services. + RemotesMap sandbox_remotes_; + RemotesMap unsandboxed_remotes_; + + // Track if next service started should be sandboxed. + bool sandbox_service_ = true; + + // Set of printer drivers which require elevated permissions to operate. + // It is expected that most print drivers will succeed with the preconfigured + // sandbox permissions. Should any drivers be discovered to require more than + // that (and thus fail with access denied errors) then we need to fallback to + // performing the operation with modified restrictions. + base::flat_set<std::string> drivers_requiring_elevated_privilege_; // Override of service to use for testing. - mojo::Remote<printing::mojom::PrintBackendService>* service_remote_for_test_ = - nullptr; + mojo::Remote<printing::mojom::PrintBackendService>* + sandboxed_service_remote_for_test_ = nullptr; + mojo::Remote<printing::mojom::PrintBackendService>* + unsandboxed_service_remote_for_test_ = nullptr; }; } // namespace printing
diff --git a/chrome/browser/printing/print_backend_service_test_impl.cc b/chrome/browser/printing/print_backend_service_test_impl.cc index cd8f4ea6..1843ade 100644 --- a/chrome/browser/printing/print_backend_service_test_impl.cc +++ b/chrome/browser/printing/print_backend_service_test_impl.cc
@@ -37,7 +37,8 @@ std::unique_ptr<PrintBackendServiceTestImpl> PrintBackendServiceTestImpl::LaunchForTesting( mojo::Remote<mojom::PrintBackendService>& remote, - scoped_refptr<TestPrintBackend> backend) { + scoped_refptr<TestPrintBackend> backend, + bool sandboxed) { std::unique_ptr<PrintBackendServiceTestImpl> service = LaunchUninitialized(remote); @@ -47,7 +48,12 @@ // Register this test version of print backend service to be used instead of // launching instances out-of-process on-demand. - PrintBackendServiceManager::GetInstance().SetServiceForTesting(&remote); + if (sandboxed) { + PrintBackendServiceManager::GetInstance().SetServiceForTesting(&remote); + } else { + PrintBackendServiceManager::GetInstance().SetServiceForFallbackTesting( + &remote); + } return service; }
diff --git a/chrome/browser/printing/print_backend_service_test_impl.h b/chrome/browser/printing/print_backend_service_test_impl.h index 41838dd..cffe7199b 100644 --- a/chrome/browser/printing/print_backend_service_test_impl.h +++ b/chrome/browser/printing/print_backend_service_test_impl.h
@@ -33,9 +33,12 @@ void Init(const std::string& locale) override; // Launch the service in-process for testing using the provided backend. + // `sandboxed` identifies if this service is potentially subject to + // experiencing access-denied errors on some commands. static std::unique_ptr<PrintBackendServiceTestImpl> LaunchForTesting( mojo::Remote<mojom::PrintBackendService>& remote, - scoped_refptr<TestPrintBackend> backend); + scoped_refptr<TestPrintBackend> backend, + bool sandboxed); private: friend class PrintBackendBrowserTest; @@ -44,6 +47,10 @@ static std::unique_ptr<PrintBackendServiceTestImpl> LaunchUninitialized( mojo::Remote<mojom::PrintBackendService>& remote); + // When pretending to be sandboxed, have the possibility of getting access + // denied errors. + bool is_sandboxed_ = false; + scoped_refptr<TestPrintBackend> test_print_backend_; };
diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn index 691b53e..15f69bd 100644 --- a/chrome/browser/profiles/BUILD.gn +++ b/chrome/browser/profiles/BUILD.gn
@@ -39,6 +39,7 @@ "//components/data_reduction_proxy/core/browser", "//components/keyed_service/content", "//components/language/core/browser", + "//components/live_caption:constants", "//components/media_router/common", "//components/pref_registry", "//components/profile_metrics",
diff --git a/chrome/browser/profiles/DEPS b/chrome/browser/profiles/DEPS index a662808e..dbdc3fe9 100644 --- a/chrome/browser/profiles/DEPS +++ b/chrome/browser/profiles/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+ash/components/account_manager", + "+components/live_caption:constants", "+components/profile_metrics", ]
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 2c5ce26..7f6c64b 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc
@@ -23,6 +23,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/language/core/browser/pref_names.h" +#include "components/live_caption/pref_names.h" #include "components/media_router/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/profile_metrics/browser_profile_type.h"
diff --git a/chrome/browser/reputation/local_heuristics.cc b/chrome/browser/reputation/local_heuristics.cc index 2ccd50e0..ff9970c 100644 --- a/chrome/browser/reputation/local_heuristics.cc +++ b/chrome/browser/reputation/local_heuristics.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/lookalikes/lookalike_url_navigation_throttle.h" #include "chrome/browser/lookalikes/lookalike_url_service.h" #include "chrome/common/chrome_features.h" +#include "components/lookalikes/core/features.h" #include "components/lookalikes/core/lookalike_url_util.h" #include "components/reputation/core/safety_tips_config.h" #include "components/security_state/core/features.h" @@ -27,8 +28,9 @@ const base::FeatureParam<bool> kEnableLookalikeEditDistanceSiteEngagement{ &security_state::features::kSafetyTipUI, "editdistance_siteengagement", true}; -const base::FeatureParam<bool> kEnableLookalikeTargetEmbedding{ - &security_state::features::kSafetyTipUI, "targetembedding", false}; +const base::FeatureParam<bool> kEnableTargetEmbeddingSafetyTips{ + &lookalikes::features::kDetectTargetEmbeddingLookalikes, "safety_tips", + true}; // Binary search through |words| to find |needle|. bool SortedWordListContains(const std::string& needle, @@ -64,7 +66,7 @@ base::BindRepeating( &reputation::IsTargetHostAllowlistedBySafetyTipsComponent, config); if (!GetMatchingDomain(navigated_domain, engaged_sites, in_target_allowlist, - &matched_domain, &match_type)) { + config, &matched_domain, &match_type)) { return false; } @@ -103,7 +105,12 @@ // Target Embedding should block URL Navigation. return false; case LookalikeUrlMatchType::kTargetEmbeddingForSafetyTips: - return kEnableLookalikeTargetEmbedding.Get(); + // Require that target embedding is enabled globally *and* the feature + // parameter for safety tips is enabled, too. This allows disabling only + // safety tips by enabling the feature and unsetting this parameter. + return base::FeatureList::IsEnabled( + lookalikes::features::kDetectTargetEmbeddingLookalikes) && + kEnableTargetEmbeddingSafetyTips.Get(); case LookalikeUrlMatchType::kSkeletonMatchTop5k: return is_safety_tip_for_simplified_domains_enabled || kEnableLookalikeTopSites.Get();
diff --git a/chrome/browser/reputation/url_elision_policy_unittest.cc b/chrome/browser/reputation/url_elision_policy_unittest.cc index 7eb0f12..e130de59 100644 --- a/chrome/browser/reputation/url_elision_policy_unittest.cc +++ b/chrome/browser/reputation/url_elision_policy_unittest.cc
@@ -76,7 +76,7 @@ // ...but not when allowlisted. reputation::SetSafetyTipAllowlistPatterns( - {"alongbutstillallowlisteddomain.com/"}, {}); + {"alongbutstillallowlisteddomain.com/"}, {}, {}); EXPECT_FALSE(ShouldElideToRegistrableDomain(kUrl)); }
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index 80b30c8..1ce480f 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -53,6 +53,7 @@ "chromeos/login:resources", "chromeos/multidevice_internals:resources", "chromeos/network_ui:resources", + "chromeos/projector:resources", "nearby_internals:resources", "nearby_share:resources", "settings/chromeos:resources", @@ -141,6 +142,7 @@ if (is_chromeos_ash) { deps += [ "chromeos:closure_compile", + "chromeos/projector:closure_compile", "nearby_share:closure_compile", "nearby_share/shared:closure_compile", "nearby_share/shared:closure_compile_module",
diff --git a/chrome/browser/resources/bookmarks/toolbar.js b/chrome/browser/resources/bookmarks/toolbar.js index 9b603b5..0e5cdde 100644 --- a/chrome/browser/resources/bookmarks/toolbar.js +++ b/chrome/browser/resources/bookmarks/toolbar.js
@@ -3,13 +3,13 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js'; import 'chrome://resources/cr_elements/icons.m.js'; import './shared_style.js'; import './strings.m.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {StoreObserver} from 'chrome://resources/js/cr/ui/store.m.js'; import {StoreClientInterface as CrUiStoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.m.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js index 5778472..47b0165 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js
@@ -14,17 +14,18 @@ const SelectToSpeakPanelAction = chrome.accessibilityPrivate.SelectToSpeakPanelAction; -// This must be the same as in ash/system/accessibility/select_to_speak_tray.cc: +// This must be the same as in +// ash/system/accessibility/select_to_speak/select_to_speak_tray.cc: // ash::kSelectToSpeakTrayClassName. export const SELECT_TO_SPEAK_TRAY_CLASS_NAME = 'tray/TrayBackgroundView/SelectToSpeakTray'; // This must match the name of view class that implements the menu view: -// ash/system/accessibility/select_to_speak_menu_view.h +// ash/system/accessibility/select_to_speak/select_to_speak_menu_view.h const SELECT_TO_SPEAK_MENU_CLASS_NAME = 'SelectToSpeakMenuView'; // This must match the name of view class that implements the speed view: -// ash/system/accessibility/select_to_speak_speed_view.h +// ash/system/accessibility/select_to_speak/select_to_speak_speed_view.h const SELECT_TO_SPEAK_SPEED_CLASS_NAME = 'SelectToSpeakSpeedView'; // This must match the name of view class that implements the bubble views: @@ -396,4 +397,4 @@ return n.className === SELECT_TO_SPEAK_TRAY_CLASS_NAME; }) !== undefined; } -} \ No newline at end of file +}
diff --git a/chrome/browser/resources/chromeos/projector/BUILD.gn b/chrome/browser/resources/chromeos/projector/BUILD.gn index 5e7155b05..e8e8312d 100644 --- a/chrome/browser/resources/chromeos/projector/BUILD.gn +++ b/chrome/browser/resources/chromeos/projector/BUILD.gn
@@ -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("//chrome/common/features.gni") import("//third_party/closure_compiler/compile_js.gni") import("//tools/grit/grit_rule.gni") import("//ui/webui/resources/tools/generate_grd.gni") @@ -15,13 +14,12 @@ input_files = [ "selfie_cam.html", "selfie_cam.js", + "selfie_cam.css", ] input_files_base_dir = rebase_path(".", "//") } grit("resources") { - defines = chrome_grit_defines - # These arguments are needed since the grd is generated at build time. enable_input_discovery_for_gn_analyze = false source = "$target_gen_dir/resources.grd"
diff --git a/chrome/browser/resources/chromeos/projector/selfie_cam.css b/chrome/browser/resources/chromeos/projector/selfie_cam.css new file mode 100644 index 0000000..f2366de --- /dev/null +++ b/chrome/browser/resources/chromeos/projector/selfie_cam.css
@@ -0,0 +1,21 @@ +/* Copyright 2021 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +body { + background-color: transparent; + bottom: 0; + height: 100%; + left: 0; + margin: 0; + top: 0; + width: 100%; +} + +.flip-horizontally { + transform: scaleX(-1); +} + +.circular { + border-radius: 50%; +}
diff --git a/chrome/browser/resources/chromeos/projector/selfie_cam.html b/chrome/browser/resources/chromeos/projector/selfie_cam.html index 7736ca0..3e260b4 100644 --- a/chrome/browser/resources/chromeos/projector/selfie_cam.html +++ b/chrome/browser/resources/chromeos/projector/selfie_cam.html
@@ -6,8 +6,11 @@ <!DOCTYPE html> <html> + <head> + <link rel="stylesheet" href="selfie_cam.css"> + </head> <body> - <video autoplay></video> + <video class="flip-horizontally circular" autoplay></video> <script type="module" src="selfie_cam.js"></script> </body> </html>
diff --git a/chrome/browser/resources/chromeos/projector/selfie_cam.js b/chrome/browser/resources/chromeos/projector/selfie_cam.js index 33d8ca1..84428b06 100644 --- a/chrome/browser/resources/chromeos/projector/selfie_cam.js +++ b/chrome/browser/resources/chromeos/projector/selfie_cam.js
@@ -2,12 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Grabs video feed from user's camera. If the user's device does not have a -// camera, then the error is caught below. -navigator.mediaDevices.getUserMedia({video: true}) - .then(stream => { - document.body.querySelector('video').srcObject = stream; - }) - .catch(err => { - console.error(err.name + ': ' + err.message); - }); +/** + * Grabs video feed from user's camera. If the user's device does not have a + * camera, then the error is caught below. + * @param {!MediaStreamConstraints} constraints + */ +async function getMedia(constraints) { + let stream = null; + try { + stream = await navigator.mediaDevices.getUserMedia(constraints); + document.body.querySelector('video').srcObject = stream; + } catch (err) { + console.error(err.name + ': ' + err.message); + } +} + +// Since the selfie cam is circular, we want equal width and height. +document.addEventListener('DOMContentLoaded', function() { + getMedia({video: {width: window.innerWidth, height: window.innerHeight}}); +}, false);
diff --git a/chrome/browser/resources/download_shelf/download_button.html b/chrome/browser/resources/download_shelf/download_button.html index 1bed746..837e39c 100644 --- a/chrome/browser/resources/download_shelf/download_button.html +++ b/chrome/browser/resources/download_shelf/download_button.html
@@ -13,7 +13,9 @@ cursor: pointer; font-family: Roboto; font-weight: 500; + min-width: 79px; padding: 8px 16px; + text-align: center; transition: background-color 300ms; user-select: none; }
diff --git a/chrome/browser/resources/download_shelf/download_item.html b/chrome/browser/resources/download_shelf/download_item.html index 9f10fea20..66fd83f 100644 --- a/chrome/browser/resources/download_shelf/download_item.html +++ b/chrome/browser/resources/download_shelf/download_item.html
@@ -5,7 +5,8 @@ --pi: 3.14159265358979; --spinner-color: var(--google-grey-900-rgb); --text-width: 140px; - --warn-text-width: 245px; + --warn-text-width: 241px; + --warn-save-text-width: 318px; --transparent-button-color: rgba(0, 0, 0, 0); } @@ -104,7 +105,8 @@ border: none; border-radius: 4px; height: 32px; - margin: 8px; + margin-inline-end: 4px; + margin-inline-start: 8px; transition: background-color 300ms; width: 32px; z-index: 2; @@ -154,6 +156,7 @@ #separator { background-color: rgba(0, 0, 0, .1); height: 90%; + margin-inline-start: 4px; width: 1px; } @@ -162,8 +165,15 @@ line-height: 150%; } +#save-button { + display: none; + margin-inline-start: 4px; + z-index: 2; +} + #discard-button { display: none; + margin-inline-start: 4px; z-index: 2; } @@ -171,21 +181,33 @@ width: var(--warn-text-width); } -[data-display-mode='warn'] .progress { +[data-display-mode='warn-save'] #text-container { + width: var(--warn-save-text-width); +} + +[data-display-mode^='warn'] .progress { padding: 0 0 0 3px; } -[data-display-mode='warn'] #discard-button, -[data-display-mode='warn'] #error-icon, -[data-display-mode='warn'] #warning-text { +[data-display-mode^='warn'] #discard-button, +[data-display-mode^='warn'] #error-icon, +[data-display-mode^='warn'] #warning-text { display: block; } -[data-display-mode='warn'] #shadow-mask, -[data-display-mode='warn'] #file-icon, -[data-display-mode='warn'] #filename, -[data-display-mode='warn'] #status-text, -[data-display-mode='warn'] .progress-indicator { +[data-display-mode^='warn'] #shadow-mask, +[data-display-mode^='warn'] #file-icon, +[data-display-mode^='warn'] #filename, +[data-display-mode^='warn'] #status-text, +[data-display-mode^='warn'] .progress-indicator { + display: none; +} + +[data-display-mode='warn-save'] #save-button { + display: block; +} + +[data-display-mode='warn-save'] #dropdown-button { display: none; } @@ -212,6 +234,7 @@ <div id="status-text"></div> <div id="warning-text"></div> </div> + <download-button id="save-button"></download-button> <download-button id="discard-button"></download-button> <button id="dropdown-button"> <svg id="dropdown-icon" viewBox="0 0 16 16">
diff --git a/chrome/browser/resources/download_shelf/download_item.js b/chrome/browser/resources/download_shelf/download_item.js index 1b465154..1b20d98a 100644 --- a/chrome/browser/resources/download_shelf/download_item.js +++ b/chrome/browser/resources/download_shelf/download_item.js
@@ -10,6 +10,7 @@ import './download_button.js'; import './strings.m.js'; +import {assert} from 'chrome://resources/js/assert.m.js'; import {CustomElement} from 'chrome://resources/js/custom_element.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; @@ -18,8 +19,12 @@ /** @enum {string} */ const DisplayMode = { + // Shows icon + filename + context menu button. kNormal: 'normal', - kWarn: 'warn' + // Shows icon + warning text + discard button + context menu button. + kWarn: 'warn', + // Shows icon + warning text + save button + discard button. + kWarnSave: 'warn-save' }; export class DownloadItemElement extends CustomElement { @@ -60,6 +65,25 @@ return this.item_; } + /** + * @private + * @return {string} + */ + get clampedWarningText_() { + // Views uses ui/gfx/text_elider.cc to elide text given a maximum width. + // For simplicity, we instead elide text by restricting text length. + const maxFilenameLength = 19; + const warningText = this.item.warningText; + if (!warningText) { + return ''; + } + + const filepath = this.item.fileNameDisplayString; + const filename = filepath.substring(filepath.lastIndexOf('/') + 1); + return warningText.replace( + filename, this.elideFilename_(filename, maxFilenameLength)); + } + /** @private */ update_() { const item = this.item_; @@ -102,11 +126,18 @@ this.$('#file-icon').src = icon; }); - downloadElement.dataset.displayMode = - this.item_.mode === DownloadMode.kNormal ? DisplayMode.kNormal : - DisplayMode.kWarn; - this.$('#warning-text').innerText = - item.warningText ? item.warningText : ''; + if (item.mode === DownloadMode.kNormal) { + downloadElement.dataset.displayMode = DisplayMode.kNormal; + } else if ( + item.mode === DownloadMode.kDangerous || + item.mode === DownloadMode.kMixedContentWarn) { + downloadElement.dataset.displayMode = DisplayMode.kWarnSave; + } else { + downloadElement.dataset.displayMode = DisplayMode.kWarn; + } + + this.$('#save-button').innerText = item.warningConfirmButtonText; + this.$('#warning-text').innerText = this.clampedWarningText_; } /** @param {number} value */ @@ -135,6 +166,30 @@ // TODO(crbug.com/1182529): Notify C++ through mojo. Remove this item // from download_list. } + + /** + * Elide a filename to a maximum length. + * The extension of the filename will be kept if it has one. + * @param {string} s A filename. + * @param {number} maxlen The maximum length after elided. + * @private + */ + elideFilename_(s, maxlen) { + assert(maxlen > 6); + + if (s.length <= maxlen) { + return s; + } + + const extIndex = s.lastIndexOf('.'); + if (extIndex === -1) { + // |s| does not have an extension. + return s.substr(0, maxlen - 3) + '...'; + } else { + const subfix = '...' + s.substr(extIndex); + return s.substr(0, maxlen - subfix.length) + subfix; + } + } } customElements.define('download-item', DownloadItemElement);
diff --git a/chrome/browser/resources/downloads/toolbar.js b/chrome/browser/resources/downloads/toolbar.js index e46911df..baf9b705 100644 --- a/chrome/browser/resources/downloads/toolbar.js +++ b/chrome/browser/resources/downloads/toolbar.js
@@ -4,7 +4,6 @@ import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import 'chrome://resources/cr_elements/hidden_style_css.m.js'; import 'chrome://resources/cr_elements/icons.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; @@ -13,6 +12,7 @@ import './strings.m.js'; import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/feed_internals/feed_internals.html b/chrome/browser/resources/feed_internals/feed_internals.html index 8dd40627..70797978 100644 --- a/chrome/browser/resources/feed_internals/feed_internals.html +++ b/chrome/browser/resources/feed_internals/feed_internals.html
@@ -27,6 +27,13 @@ <body> + <h2>Web Feed</h2> + <label> + <input type="checkbox" id="enable-webfeed-follow-intro-debug" + name="enable-webfeed-follow-intro-debug"> + <strong>Enable IPH debug mode</strong> + </label> + <h2>Properties</h2> <table> <tr> @@ -179,15 +186,5 @@ <h2>Feed Stream Data</h2> <input id="feed-stream-data-file" type="file"> <button id="feed-stream-data-override">Override</button> - - <h2>WebFeed UI</h2> - <p>WebFeed Follow Intro Debug enabled: </p> - <p id="webfeed-follow-intro-debug-enabled-status"></p> - <label> - <input type="checkbox" id="enable-webfeed-follow-intro-debug" - name="enable-webfeed-follow-intro-debug"> - Enable WebFeed Follow Intro Debug - </label> - <button id="enable-webfeed-follow-intro-debug-apply">Apply</button> </body> </html>
diff --git a/chrome/browser/resources/feed_internals/feed_internals.js b/chrome/browser/resources/feed_internals/feed_internals.js index 149573f0..837d638 100644 --- a/chrome/browser/resources/feed_internals/feed_internals.js +++ b/chrome/browser/resources/feed_internals/feed_internals.js
@@ -26,8 +26,9 @@ $('load-stream-status').textContent = properties.loadStreamStatus; $('feed-fetch-url').textContent = properties.feedFetchUrl.url; $('feed-actions-url').textContent = properties.feedActionsUrl.url; - $('webfeed-follow-intro-debug-enabled-status').textContent = + $('enable-webfeed-follow-intro-debug').checked = properties.isWebFeedFollowIntroDebugEnabled; + $('enable-webfeed-follow-intro-debug').disabled = false; }); } @@ -169,11 +170,11 @@ } }); - $('enable-webfeed-follow-intro-debug-apply') - .addEventListener('click', function() { - pageHandler.setWebFeedFollowIntroDebugEnabled( - $('enable-webfeed-follow-intro-debug').checked); - }); + $('enable-webfeed-follow-intro-debug').addEventListener('click', function() { + pageHandler.setWebFeedFollowIntroDebugEnabled( + $('enable-webfeed-follow-intro-debug').checked); + $('enable-webfeed-follow-intro-debug').disabled = true; + }); } function updatePage() {
diff --git a/chrome/browser/resources/history/history_toolbar.js b/chrome/browser/resources/history/history_toolbar.js index ae712d0..6fd5cf1 100644 --- a/chrome/browser/resources/history/history_toolbar.js +++ b/chrome/browser/resources/history/history_toolbar.js
@@ -3,10 +3,11 @@ // found in the LICENSE file. import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import './shared_style.js'; import './strings.m.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/memories/app.js b/chrome/browser/resources/memories/app.js index 598ab47..ca2b496 100644 --- a/chrome/browser/resources/memories/app.js +++ b/chrome/browser/resources/memories/app.js
@@ -9,13 +9,14 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import 'chrome://resources/polymer/v3_0/iron-scroll-threshold/iron-scroll-threshold.js'; import {MemoriesResult, PageCallbackRouter, PageHandlerRemote} from '/chrome/browser/ui/webui/memories/memories.mojom-webui.js'; import {Visit} from '/components/history_clusters/core/memories.mojom-webui.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {UnguessableToken} from 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-webui.js'; import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html index 096c027..0ee0445 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.html
@@ -111,9 +111,11 @@ </div> </div> <div id="alignEnd"> - <paper-spinner-lite id="inhibitedSpinner" - active="[[isDeviceInhibited_]]"> - </paper-spinner-lite> + <template is="dom-if" if="[[canShowSpinner]]" restamp> + <paper-spinner-lite id="inhibitedSpinner" + active="[[isDeviceInhibited_]]"> + </paper-spinner-lite> + </template> <template is="dom-if" if="[[showAddESimButton_(cellularDeviceState, globalPolicy)]]" restamp> <cr-icon-button class="icon-add-cellular add-button"
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js index 42f59bf..37b36ea 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/cellular_networks_list.js
@@ -45,6 +45,15 @@ }, /** + * If true, inhibited spinner can be shown, it will be shown + * if true and cellular is inhibited. + * @type {boolean} + */ + canShowSpinner: { + type: Boolean, + }, + + /** * Device state for the tether network type. This device state should be * used for instant tether networks. * @type {!OncMojo.DeviceStateProperties|undefined}
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html index 5acbd417..b9012a3 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
@@ -161,7 +161,8 @@ global-policy="[[globalPolicy_]]" vpn-providers="[[vpnProviders_]]" show-spinner="{{showSpinner_}}" - is-connected-to-non-cellular-network="[[isConnectedToNonCellularNetwork_]]"> + is-connected-to-non-cellular-network="[[isConnectedToNonCellularNetwork_]]" + is-cellular-setup-active="[[showCellularSetupDialog_]]"> </settings-internet-subpage> </settings-subpage> </template>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html index aee6113..7ce6b313 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.html
@@ -184,7 +184,8 @@ cellular-device-state="[[deviceState]]" tether-device-state="[[tetherDeviceState]]" global-policy="[[globalPolicy]]" - is-connected-to-non-cellular-network="[[isConnectedToNonCellularNetwork]]"> + is-connected-to-non-cellular-network="[[isConnectedToNonCellularNetwork]]" + can-show-spinner="[[!isCellularSetupActive]]"> </cellular-networks-list> </template>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js index e783316e..fe753226 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js
@@ -65,6 +65,10 @@ type: Boolean, }, + isCellularSetupActive: { + type: Boolean, + }, + /** * List of all network state data for the network type. * @private {!Array<!OncMojo.NetworkStateProperties>}
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index 674b00b..79a3a158 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -257,6 +257,8 @@ "chrome/browser/resources/settings/chromeos/os_settings_page/main_page_behavior.html|MainPageBehavior", "chrome/browser/resources/settings/chromeos/search_handler.html|getSearchHandler, setSearchHandlerForTesting", "ui/webui/resources/cr_components/chromeos/network/network_listener_behavior.html|NetworkListenerBehavior", + "ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html|CrToolbarElement", + "ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html|CrToolbarSearchFieldElement", "ui/webui/resources/cr_elements/cr_slider/cr_slider.html|SliderTick", "ui/webui/resources/html/assert.html|assert,assertNotReached", "ui/webui/resources/html/cr.html|sendWithPromise,removeWebUIListener,addWebUIListener,WebUIListener",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html index b86d9167..09a6da6 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/cr_drawer/cr_drawer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_page_host_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js index e8f45136e..2c1b249 100644 --- a/chrome/browser/resources/settings/settings.js +++ b/chrome/browser/resources/settings/settings.js
@@ -4,6 +4,8 @@ import './settings_ui/settings_ui.js'; +export {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +export {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; export {PluralStringProxyImpl as SettingsPluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js'; export {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, PromoteUpdaterStatus, UpdateStatus} from './about_page/about_page_browser_proxy.js'; export {AppearanceBrowserProxy, AppearanceBrowserProxyImpl} from './appearance_page/appearance_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js index be9ccf4..b45f56f3 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -12,7 +12,6 @@ */ import 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js'; import 'chrome://resources/cr_elements/cr_page_host_style_css.js'; -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import 'chrome://resources/cr_elements/icons.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; @@ -24,6 +23,8 @@ import '../settings_vars_css.js'; import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {FindShortcutBehavior} from 'chrome://resources/cr_elements/find_shortcut_behavior.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {isChromeOS} from 'chrome://resources/js/cr.m.js';
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc index a9069959..9d7d059 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -503,8 +503,6 @@ base::BindOnce(&CheckClientDownloadRequestBase::OnURLLoaderComplete, GetWeakPtr())); request_start_time_ = base::TimeTicks::Now(); - UMA_HISTOGRAM_COUNTS_1M("SBClientDownload.DownloadRequestPayloadSize", - client_download_request_data_.size()); // Add the access token to the proto for display on chrome://safe-browsing client_download_request_->set_access_token(access_token_);
diff --git a/chrome/browser/service_sandbox_type.h b/chrome/browser/service_sandbox_type.h index 2192ca6..b9ac6749 100644 --- a/chrome/browser/service_sandbox_type.h +++ b/chrome/browser/service_sandbox_type.h
@@ -9,8 +9,15 @@ #include "build/chromeos_buildflags.h" #include "content/public/browser/service_process_host.h" #include "media/base/media_switches.h" +#include "printing/buildflags/buildflags.h" #include "sandbox/policy/sandbox_type.h" +#if (defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ + defined(OS_CHROMEOS)) && \ + BUILDFLAG(ENABLE_PRINTING) +#include "chrome/browser/printing/print_backend_service_manager.h" +#endif + // This file maps service classes to sandbox types. Services which // require a non-utility sandbox can be added here. See // ServiceProcessHost::Launch() for how these templates are consumed. @@ -90,8 +97,22 @@ } #endif // !defined(OS_ANDROID) +// mirroring::mojom::MirroringService +#if defined(OS_MAC) +namespace mirroring { +namespace mojom { +class MirroringService; +} +} // namespace mirroring +template <> +inline sandbox::policy::SandboxType +content::GetServiceSandboxType<mirroring::mojom::MirroringService>() { + return sandbox::policy::SandboxType::kMirroring; +} +#endif // OS_MAC + // printing::mojom::PrintingService -#if defined(OS_WIN) +#if defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW) namespace printing { namespace mojom { class PrintingService; @@ -103,8 +124,12 @@ content::GetServiceSandboxType<printing::mojom::PrintingService>() { return sandbox::policy::SandboxType::kPdfConversion; } -#endif // defined(OS_WIN) +#endif // defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW) +// printing::mojom::PrintBackendService +#if (defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ + defined(OS_CHROMEOS)) && \ + BUILDFLAG(ENABLE_PRINTING) namespace printing { namespace mojom { class PrintBackendService; @@ -114,8 +139,14 @@ template <> inline sandbox::policy::SandboxType content::GetServiceSandboxType<printing::mojom::PrintBackendService>() { - return sandbox::policy::SandboxType::kPrintBackend; + return printing::PrintBackendServiceManager::GetInstance() + .ShouldSandboxPrintBackendService() + ? sandbox::policy::SandboxType::kPrintBackend + : sandbox::policy::SandboxType::kNoSandbox; } +#endif // (defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || + // defined(OS_CHROMEOS)) && + // BUILDFLAG(ENABLE_PRINTING) // proxy_resolver::mojom::ProxyResolverFactory #if defined(OS_WIN)
diff --git a/chrome/browser/sessions/session_restore_interactive_uitest.cc b/chrome/browser/sessions/session_restore_interactive_uitest.cc index f2e4dce..500c97e0 100644 --- a/chrome/browser/sessions/session_restore_interactive_uitest.cc +++ b/chrome/browser/sessions/session_restore_interactive_uitest.cc
@@ -124,16 +124,9 @@ Browser* restored = QuitBrowserAndRestore(browser(), 3); EXPECT_EQ(1, restored->tab_strip_model()->count()); -#if defined(OS_MAC) - // On macOS, minimized windows are neither active nor shown, to avoid causing - // space switches during session restore. - EXPECT_FALSE(restored->window()->IsActive()); - EXPECT_FALSE(restored->window()->IsVisible()); -#else // Expect the window to be visible. // Prior to the fix for https://crbug.com/1018885, the window was active but // not visible. EXPECT_TRUE(restored->window()->IsActive()); EXPECT_TRUE(restored->window()->IsVisible()); -#endif }
diff --git a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc index 845c052..99b690d 100644 --- a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc +++ b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include "chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/speech/cros_speech_recognition_service_factory.h" #include "chrome/browser/speech/fake_speech_recognition_service.h" @@ -15,6 +14,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/soda/soda_installer.h" +#include "components/soda/soda_installer_impl_chromeos.h" #include "content/public/test/browser_test.h" #include "media/audio/audio_system.h" #include "media/base/audio_parameters.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index bf4821d..074584a 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -456,6 +456,7 @@ "//components/language/core/browser", "//components/language/core/common", "//components/lens", + "//components/live_caption:constants", "//components/lookalikes/core", "//components/metrics_services_manager", "//components/navigation_metrics", @@ -2455,6 +2456,8 @@ "webui/chromeos/power_ui.h", "webui/chromeos/projector/projector_ui.cc", "webui/chromeos/projector/projector_ui.h", + "webui/chromeos/projector/selfie_cam_bubble_manager.cc", + "webui/chromeos/projector/selfie_cam_bubble_manager.h", "webui/chromeos/set_time_ui.cc", "webui/chromeos/set_time_ui.h", "webui/chromeos/slow_trace_ui.cc", @@ -2690,7 +2693,6 @@ "//chrome/browser/resources:internet_config_dialog_resources", "//chrome/browser/resources:internet_detail_dialog_resources", "//chrome/browser/resources/chromeos:multidevice_setup_resources", - "//chrome/browser/resources/chromeos/projector:resources", "//chrome/browser/ui/app_list/search/cros_action_history:cros_action_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:app_launch_event_logger_proto", "//chrome/browser/ui/app_list/search/search_result_ranker:app_launch_predictor_proto", @@ -4418,7 +4420,6 @@ "//components/content_settings/browser/ui", "//components/fullscreen_control", "//components/live_caption", - "//components/live_caption:constants", "//components/media_message_center", "//components/page_info", "//components/payments/content",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 991c723..8cbf8ab 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1478,6 +1478,9 @@ <message name="IDS_DOWNLOAD_LOCATION_DIALOG_TITLE" desc="Title for the dialog that asks where the user wants to save the download file before the download begins."> Choose where to download </message> + <message name="IDS_DOWNLOAD_LOCATION_DIALOG_TITLE_CONFIRM_DOWNLOAD" desc="Title for the dialog that informs the user to confirm the download."> + Confirm download + </message> <message name="IDS_DOWNLOAD_LOCATION_DIALOG_CHECKBOX" desc="Label for the checkbox that allows the user to indicate if they do not want the download location selection dialog to appear every time they initiate a download."> Don‘t show again </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DOWNLOAD_LOCATION_DIALOG_TITLE_CONFIRM_DOWNLOAD.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DOWNLOAD_LOCATION_DIALOG_TITLE_CONFIRM_DOWNLOAD.png.sha1 new file mode 100644 index 0000000..7266b52 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_DOWNLOAD_LOCATION_DIALOG_TITLE_CONFIRM_DOWNLOAD.png.sha1
@@ -0,0 +1 @@ +bb34c052c6ec63ae5659f657adea0dec4dbcf1b9 \ No newline at end of file
diff --git a/chrome/browser/ui/android/webid/BUILD.gn b/chrome/browser/ui/android/webid/BUILD.gn index 8e520b5..7661bbff 100644 --- a/chrome/browser/ui/android/webid/BUILD.gn +++ b/chrome/browser/ui/android/webid/BUILD.gn
@@ -7,6 +7,7 @@ android_library("public_java") { deps = [ "//base:base_java", + "//components/browser_ui/bottomsheet/android:java", "//third_party/androidx:androidx_annotation_annotation_java", "//ui/android:ui_java", ]
diff --git a/chrome/browser/ui/android/webid/DEPS b/chrome/browser/ui/android/webid/DEPS new file mode 100644 index 0000000..1c417c3 --- /dev/null +++ b/chrome/browser/ui/android/webid/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+chrome/android", + "+components/browser_ui/bottomsheet/android", +]
diff --git a/chrome/browser/ui/android/webid/README.md b/chrome/browser/ui/android/webid/README.md index eaddf26..e4cb4036 100644 --- a/chrome/browser/ui/android/webid/README.md +++ b/chrome/browser/ui/android/webid/README.md
@@ -15,8 +15,7 @@ #### java/ The root folder contains the public interface of this component and data that is -used to fill it with content, e.g. Account. This folder also contains the -factory to instantiate the component. +used to fill it with content, e.g. Accounts. Add `chrome/browser/ui/android/webid/android:public_java` as dependency to use the interface and classes defined here. @@ -27,5 +26,23 @@ outside of this package. If you need access to any method, consider making it part of the public interface as defined in `AccountSelectionComponent` -At the moment the implementation is a simple stub that selects the first -account. +This folder contains a separate [README](internal/README.md) that explains in +detail how the architecture looks like and how to extend the component further. + +## Example usage + +``` java + +// Currently, you need access to internal/ to instantiate the component: +AccountSelectionComponent component = new AccountSelectionCoordinator(/*...*/); + +component.initialize(activity, activity.getBottomSheetController(), () -> { + // Things to do when the component is dismissed. +})); + +List<Account> accounts; // Add accounts to show! +component.showAccounts("www.displayed-url.example", accounts, (account) -> { + // The |account| that was clicked should be used to fill something now. +}) + +```
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.cc b/chrome/browser/ui/android/webid/account_selection_view_android.cc index 07653413..39e35a6 100644 --- a/chrome/browser/ui/android/webid/account_selection_view_android.cc +++ b/chrome/browser/ui/android/webid/account_selection_view_android.cc
@@ -28,9 +28,10 @@ namespace { -std::vector<std::string> ConvertAccountToFields(const Account& account) { +std::vector<std::string> ConvertAccountToFields(const Account& account, + const GURL& idp_url) { return {account.sub, account.email, account.name, - account.given_name, account.picture, ""}; + account.given_name, account.picture, idp_url.spec()}; } Account ConvertFieldsToAccount(JNIEnv* env, @@ -59,7 +60,8 @@ } } -void AccountSelectionViewAndroid::Show(const GURL& url, +void AccountSelectionViewAndroid::Show(const GURL& rp_url, + const GURL& idp_url, base::span<const Account> accounts) { if (!RecreateJavaObject()) { // It's possible that the constructor cannot access the bottom sheet clank @@ -68,12 +70,12 @@ delegate_->OnDismiss(); return; } + // Serialize the |accounts| span into a Java array and instruct the bridge // to show it together with |url| to the user. - // TODO(majidvp): Pass the serialized IdP GURL as part of the account to UI. std::vector<std::vector<std::string>> accounts_fields(accounts.size()); for (size_t i = 0; i < accounts.size(); ++i) { - accounts_fields[i] = ConvertAccountToFields(accounts[i]); + accounts_fields[i] = ConvertAccountToFields(accounts[i], idp_url); } JNIEnv* env = AttachCurrentThread(); @@ -82,7 +84,7 @@ base::android::ToJavaArrayOfStringArray(env, accounts_fields); Java_AccountSelectionBridge_showAccounts( - env, java_object_internal_, ConvertUTF8ToJavaString(env, url.spec()), + env, java_object_internal_, ConvertUTF8ToJavaString(env, rp_url.spec()), accounts_fields_obj); } @@ -105,7 +107,7 @@ Java_AccountSelectionBridge_destroy(AttachCurrentThread(), java_object_internal_); } - java_object_internal_ = Java_AccountSelectionBridge_Constructor( + java_object_internal_ = Java_AccountSelectionBridge_create( AttachCurrentThread(), reinterpret_cast<intptr_t>(this), delegate_->GetNativeView()->GetWindowAndroid()->GetJavaObject()); return !!java_object_internal_;
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.h b/chrome/browser/ui/android/webid/account_selection_view_android.h index 0880f9a..1c3fdc9 100644 --- a/chrome/browser/ui/android/webid/account_selection_view_android.h +++ b/chrome/browser/ui/android/webid/account_selection_view_android.h
@@ -18,7 +18,9 @@ ~AccountSelectionViewAndroid() override; // AccountSelectionView: - void Show(const GURL& url, base::span<const Account> accounts) override; + void Show(const GURL& rp_url, + const GURL& idp_url, + base::span<const Account> accounts) override; void OnAccountSelected( JNIEnv* env,
diff --git a/chrome/browser/ui/android/webid/internal/BUILD.gn b/chrome/browser/ui/android/webid/internal/BUILD.gn index 8706a494..ccfa7f6 100644 --- a/chrome/browser/ui/android/webid/internal/BUILD.gn +++ b/chrome/browser/ui/android/webid/internal/BUILD.gn
@@ -12,12 +12,23 @@ "//base:base_java", "//base:jni_java", "//chrome/android:chrome_java", + "//chrome/browser/flags:java", "//chrome/browser/ui/android/webid:public_java", + "//chrome/browser/util:java", + "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/widget/android:java", + "//components/embedder_support/android:util_java", "//third_party/androidx:androidx_annotation_annotation_java", "//ui/android:ui_java", + "//url:gurl_java", ] - sources = [ "java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java", + "java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java", + "java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java", + "java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java", + ] resources_package = "org.chromium.chrome.browser.ui.android.webid" annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chrome/browser/ui/android/webid/internal/README.md b/chrome/browser/ui/android/webid/internal/README.md new file mode 100644 index 0000000..ed3ea2c --- /dev/null +++ b/chrome/browser/ui/android/webid/internal/README.md
@@ -0,0 +1,55 @@ +# Account Selection Android Feature + +This folder contains the internal parts of the Account Selection component. Files, +classes and methods defined in here are not meant to be used outside of this +package. + +This document provides a brief overview of the architecture. + +[TOC] + + +## Component structure + +This component follows the typical +[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) +structure that is widely used in Chrome on Android. The MVC structures separates +logic from representation: + + * The [controller](#Controller) creates and connects all subcomponents and + performs logic that affects the visual appearance of the component. + * The [model](#Model) keeps all state that affects the visual appearance of the + component. Changes made to it are automatically propagated to the view by a + Model-Change-Processor (MCP) as defined in + `//src/ui/android/java/src/org/chromium/ui/modelutil/` + * The [view](#View) is the representation of the component. It enforces styles + and is mostly called by a view binder to set mutable properties. + +## Model + +The model holds state and event listeners connected to the view. An MCP +automatically notifies listener about any change made to a property. To automate +this Observer structure, the model is a `PropertyModel` as defined in +`//src/ui/android/java/src/org/chromium/ui/modelutil/`. It is built by defining +readable and writable properties and constructing a model with them. The +properties (and a simple factory method for the model) are located in the static +`AccountSelectionProperties` class. + +The details of the model will be added in follow up patches. + +## Controller + +The controller of this model implements the AccountSelectionComponent interface as +defined in `public/` and contains all logic. The controller consists of two parts: + + * **AccountSelectionCoordinator** which implements the public interface and creates all + parts of the component (model, mediator, view, etc.) and links them using + MCPs. + * **AccountSelectionMediator** which handles request to the component API and changes + the model accordingly. Interactions with the view are typically handled here + and either affect the model or notify callers of the component API. + + +## View + +This will be added in follow-up patches.
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java index f87f9ec..5e50de73 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
@@ -4,21 +4,40 @@ package org.chromium.chrome.browser.ui.android.webid; +import androidx.annotation.Nullable; + import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.browser.ui.android.webid.data.Account; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; import org.chromium.ui.base.WindowAndroid; +import java.util.Arrays; + /** * This bridge creates and initializes a {@link AccountSelectionComponent} on construction and * forwards native calls to it. */ class AccountSelectionBridge implements AccountSelectionComponent.Delegate { private long mNativeView; + private final AccountSelectionComponent mAccountSelectionComponent; + + private AccountSelectionBridge(long nativeView, WindowAndroid windowAndroid, + BottomSheetController bottomSheetController) { + mNativeView = nativeView; + mAccountSelectionComponent = new AccountSelectionCoordinator(); + mAccountSelectionComponent.initialize( + windowAndroid.getContext().get(), bottomSheetController, this); + } @CalledByNative - private AccountSelectionBridge(long nativeView, WindowAndroid windowAndroid) { - mNativeView = nativeView; + private static @Nullable AccountSelectionBridge create( + long nativeView, WindowAndroid windowAndroid) { + BottomSheetController bottomSheetController = + BottomSheetControllerProvider.from(windowAndroid); + if (bottomSheetController == null) return null; + return new AccountSelectionBridge(nativeView, windowAndroid, bottomSheetController); } @CalledByNative @@ -36,6 +55,7 @@ */ @CalledByNative private void showAccounts(String url, String[][] accountsFields) { + assert accountsFields != null && accountsFields.length > 0; Account[] accounts = new Account[accountsFields.length]; for (int i = 0; i < accountsFields.length; i++) { String[] fields = accountsFields[i]; @@ -48,8 +68,7 @@ /* originUrl= */ fields[5]); } - // TODO(majidvp): Actually show UI that lists the account. - onAccountSelected(accounts[0]); + mAccountSelectionComponent.showAccounts(url, Arrays.asList(accounts)); } @Override
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java new file mode 100644 index 0000000..2c45ca0 --- /dev/null +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java
@@ -0,0 +1,33 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.ui.android.webid; + +import android.content.Context; + +import org.chromium.chrome.browser.ui.android.webid.data.Account; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.ui.modelutil.PropertyModel; + +import java.util.List; + +/** + * Creates the AccountSelection component. + */ +public class AccountSelectionCoordinator implements AccountSelectionComponent { + private final AccountSelectionMediator mMediator = new AccountSelectionMediator(); + private final PropertyModel mModel = AccountSelectionProperties.createDefaultModel(); + + @Override + public void initialize(Context context, BottomSheetController sheetController, + AccountSelectionComponent.Delegate delegate) { + mMediator.initialize(delegate, mModel); + // TODO(majidvp): Create the view and setup model change processor. + } + + @Override + public void showAccounts(String url, List<Account> accounts) { + mMediator.showAccounts(url, accounts); + } +}
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java new file mode 100644 index 0000000..3c9e51d2 --- /dev/null +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
@@ -0,0 +1,27 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.ui.android.webid; + +import org.chromium.chrome.browser.ui.android.webid.data.Account; +import org.chromium.ui.modelutil.PropertyModel; + +import java.util.List; + +/** + * Contains the logic for the AccountSelection component. It sets the state of the model and reacts + * to events like clicks. + */ +class AccountSelectionMediator { + private AccountSelectionComponent.Delegate mDelegate; + private PropertyModel mModel; + + void initialize(AccountSelectionComponent.Delegate delegate, PropertyModel model) { + assert delegate != null; + mDelegate = delegate; + mModel = model; + } + + void showAccounts(String url, List<Account> accounts) {} +}
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java new file mode 100644 index 0000000..46fd688 --- /dev/null +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java
@@ -0,0 +1,18 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// 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.ui.android.webid; + +import org.chromium.ui.modelutil.PropertyModel; + +/** + * Properties defined here reflect the state of the AccountSelection-components. + */ +class AccountSelectionProperties { + static PropertyModel createDefaultModel() { + return new PropertyModel(); + } + + private AccountSelectionProperties() {} +}
diff --git a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java index f176f1c..6c213fe 100644 --- a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java +++ b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java
@@ -7,6 +7,7 @@ import android.content.Context; import org.chromium.chrome.browser.ui.android.webid.data.Account; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import java.util.List; @@ -36,9 +37,10 @@ /** * Initializes the component. * @param context A {@link Context} to create views and retrieve resources. + * @param sheetController A {@link BottomSheetController} used to show/hide the sheet. * @param delegate A {@link Delegate} that handles dismiss events. */ - void initialize(Context context, Delegate delegate); + void initialize(Context context, BottomSheetController sheetController, Delegate delegate); /** * Displays the given accounts in a new bottom sheet.
diff --git a/chrome/browser/ui/app_list/app_list_test_util.cc b/chrome/browser/ui/app_list/app_list_test_util.cc index 37dc0da3..6007366 100644 --- a/chrome/browser/ui/app_list/app_list_test_util.cc +++ b/chrome/browser/ui/app_list/app_list_test_util.cc
@@ -9,7 +9,6 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/web_applications/externally_managed_app_manager_impl.h" #include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_manager.h" -#include "chrome/browser/web_applications/test/test_os_integration_manager.h" #include "chrome/browser/web_applications/test/test_web_app_provider.h" #include "chrome/browser/web_applications/test/test_web_app_url_loader.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" @@ -64,17 +63,8 @@ std::make_unique<web_app::ExternallyManagedAppManagerImpl>(profile); externally_managed_app_manager->SetUrlLoaderForTesting(std::move(url_loader)); - auto os_integration_manager = - std::make_unique<web_app::TestOsIntegrationManager>( - profile, /*app_shortcut_manager=*/nullptr, - /*file_handler_manager=*/nullptr, - /*protocol_handler_manager=*/nullptr, - /*url_handler_manager*/ nullptr); - os_integration_manager_ = os_integration_manager.get(); - - auto* provider = web_app::TestWebAppProvider::Get(profile); + auto* const provider = web_app::TestWebAppProvider::Get(profile); provider->SetExternallyManagedAppManager( std::move(externally_managed_app_manager)); - provider->SetOsIntegrationManager(std::move(os_integration_manager)); web_app::test::AwaitStartWebAppProviderAndSubsystems(profile); }
diff --git a/chrome/browser/ui/app_list/app_list_test_util.h b/chrome/browser/ui/app_list/app_list_test_util.h index e989f55e..5f31548 100644 --- a/chrome/browser/ui/app_list/app_list_test_util.h +++ b/chrome/browser/ui/app_list/app_list_test_util.h
@@ -8,7 +8,6 @@ #include "chrome/browser/extensions/extension_service_test_base.h" namespace web_app { -class TestOsIntegrationManager; class TestWebAppUrlLoader; } // namespace web_app @@ -24,15 +23,11 @@ void SetUp() override; - web_app::TestOsIntegrationManager& os_integration_manager() { - return *os_integration_manager_; - } web_app::TestWebAppUrlLoader& url_loader() { return *url_loader_; } private: void ConfigureWebAppProvider(); - web_app::TestOsIntegrationManager* os_integration_manager_ = nullptr; web_app::TestWebAppUrlLoader* url_loader_ = nullptr; };
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc index 2f89567..af110ab 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -42,9 +42,7 @@ #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h" #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h" #include "chrome/browser/web_applications/components/app_icon_manager.h" -#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_application_info.h" -#include "chrome/browser/web_applications/test/test_os_integration_manager.h" #include "chrome/browser/web_applications/test/test_web_app_provider.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -329,9 +327,6 @@ std::string CreateWebApp(const std::string& app_name) { const GURL kAppUrl("https://example.com/"); - os_integration_manager().SetNextCreateShortcutsResult( - web_app::GenerateAppIdFromURL(kAppUrl), true); - auto web_app_info = std::make_unique<WebApplicationInfo>(); web_app_info->title = base::UTF8ToUTF16(app_name); web_app_info->start_url = kAppUrl;
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc index 6299182..946f5507 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.cc +++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -57,6 +57,18 @@ recognizer_status_ = SPEECH_RECOGNIZER_OFF; } +void ProjectorClientImpl::ShowSelfieCam() { + selfie_cam_bubble_manager_.Show(ProfileManager::GetPrimaryUserProfile()); +} + +void ProjectorClientImpl::CloseSelfieCam() { + selfie_cam_bubble_manager_.Close(); +} + +bool ProjectorClientImpl::IsSelfieCamVisible() const { + return selfie_cam_bubble_manager_.IsVisible(); +} + void ProjectorClientImpl::OnSpeechResult( const std::u16string& text, bool is_final,
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.h b/chrome/browser/ui/ash/projector/projector_client_impl.h index aa92c8e..0267575 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.h +++ b/chrome/browser/ui/ash/projector/projector_client_impl.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/speech/speech_recognizer_delegate.h" +#include "chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.h" #include "components/soda/constants.h" #include "components/soda/soda_installer.h" @@ -29,8 +30,10 @@ // ash::ProjectorClient: void StartSpeechRecognition() override; - void StopSpeechRecognition() override; + void ShowSelfieCam() override; + void CloseSelfieCam() override; + bool IsSelfieCamVisible() const override; // SpeechRecognizerDelegate: void OnSpeechResult( @@ -62,6 +65,7 @@ speech::SodaInstaller::Observer> observed_soda_installer_{this}; std::unique_ptr<OnDeviceSpeechRecognizer> speech_recognizer_; + chromeos::SelfieCamBubbleManager selfie_cam_bubble_manager_; base::WeakPtrFactory<ProjectorClientImpl> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc new file mode 100644 index 0000000..fc9fcf08 --- /dev/null +++ b/chrome/browser/ui/ash/projector/projector_client_impl_browsertest.cc
@@ -0,0 +1,51 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/projector/projector_client_impl.h" + +#include <memory> + +#include "ash/constants/ash_features.h" +#include "ash/public/cpp/projector/projector_client.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/test/browser_test.h" + +namespace ash { + +class ProjectorClientTest : public InProcessBrowserTest { + public: + ProjectorClientTest() { + scoped_feature_list_.InitAndEnableFeature(features::kProjector); + } + + ~ProjectorClientTest() override = default; + ProjectorClientTest(const ProjectorClientTest&) = delete; + ProjectorClientTest& operator=(const ProjectorClientTest&) = delete; + + // InProcessBrowserTest: + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + client_ = std::make_unique<ProjectorClientImpl>(); + } + + protected: + std::unique_ptr<ProjectorClient> client_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(ProjectorClientTest, ShowOrCloseSelfieCamTest) { + EXPECT_FALSE(client_->IsSelfieCamVisible()); + client_->ShowSelfieCam(); + EXPECT_TRUE(client_->IsSelfieCamVisible()); + client_->CloseSelfieCam(); + EXPECT_FALSE(client_->IsSelfieCamVisible()); +} + +// TODO(crbug/1199396): Add a test to verify the selfie cam turns off when the +// device goes inactive. + +} // namespace ash
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc index e2c85c9..631a1902 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -578,11 +578,10 @@ extensions::EventRouter* event_router = extensions::EventRouter::Get(profile); - auto event_args = std::make_unique<base::ListValue>(); auto event = std::make_unique<extensions::Event>( extensions::events::WALLPAPER_PRIVATE_ON_CLOSE_PREVIEW_WALLPAPER, extensions::api::wallpaper_private::OnClosePreviewWallpaper::kEventName, - std::move(event_args)); + std::vector<base::Value>()); event_router->DispatchEventToExtension(kWallpaperManagerId, std::move(event)); }
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc index 393bdf80f..ce0d8e6 100644 --- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
@@ -10,6 +10,8 @@ #include "chrome/browser/ui/browser_window.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" namespace autofill { @@ -39,16 +41,14 @@ } std::u16string EditAddressProfileDialogControllerImpl::GetWindowTitle() const { - // TODO(crbug.com/1167060): Use internationalized string upon having final - // strings. - return is_update_ ? u"Update Address?" : u"Save Address?"; + return l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_TITLE); } std::u16string EditAddressProfileDialogControllerImpl::GetOkButtonLabel() const { - // TODO(crbug.com/1167060): Use internationalized string upon having final - // strings. - return is_update_ ? u"Update" : u"Save"; + return l10n_util::GetStringUTF16( + is_update_ ? IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_UPDATE + : IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE); } const AutofillProfile&
diff --git a/chrome/browser/ui/autofill/save_address_profile_icon_controller.h b/chrome/browser/ui/autofill/save_address_profile_icon_controller.h index 6b58abc..4cef9aa 100644 --- a/chrome/browser/ui/autofill/save_address_profile_icon_controller.h +++ b/chrome/browser/ui/autofill/save_address_profile_icon_controller.h
@@ -26,6 +26,8 @@ virtual bool IsBubbleActive() const = 0; + virtual std::u16string GetPageActionIconTootip() const = 0; + virtual AutofillBubbleBase* GetSaveBubbleView() const = 0; };
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc index 782cbab..4066a17d 100644 --- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
@@ -12,6 +12,8 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" namespace autofill { @@ -46,11 +48,9 @@ std::u16string SaveUpdateAddressProfileBubbleControllerImpl::GetWindowTitle() const { - // TODO(crbug.com/1167060): Use internationalized string upon having final - // strings. - // TODO(crbug.com/1167060): Update prompt title should reflect the fields that - // are being updated. - return original_profile_ ? u"Update Address?" : u"Save Address?"; + return l10n_util::GetStringUTF16( + original_profile_ ? IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE + : IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE); } const AutofillProfile& @@ -72,13 +72,13 @@ } void SaveUpdateAddressProfileBubbleControllerImpl::OnEditButtonClicked() { - HideBubble(); EditAddressProfileDialogControllerImpl::CreateForWebContents(web_contents()); EditAddressProfileDialogControllerImpl* controller = EditAddressProfileDialogControllerImpl::FromWebContents(web_contents()); controller->OfferEdit(address_profile_, /*is_update=*/original_profile_.has_value(), std::move(address_profile_save_prompt_callback_)); + HideBubble(); } void SaveUpdateAddressProfileBubbleControllerImpl::OnBubbleClosed() { @@ -98,6 +98,11 @@ return !address_profile_save_prompt_callback_.is_null(); } +std::u16string +SaveUpdateAddressProfileBubbleControllerImpl::GetPageActionIconTootip() const { + return GetWindowTitle(); +} + AutofillBubbleBase* SaveUpdateAddressProfileBubbleControllerImpl::GetSaveBubbleView() const { return bubble_view();
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h index 5e8693a..ef85394e 100644 --- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h +++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.h
@@ -55,6 +55,7 @@ // SaveAddressProfileIconController: void OnPageActionIconClicked() override; bool IsBubbleActive() const override; + std::u16string GetPageActionIconTootip() const override; AutofillBubbleBase* GetSaveBubbleView() const override; protected:
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 71ce1e2..2481cee 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -200,6 +200,9 @@ kErrorLoadingKiosk, }; + // The default value for a browser's `restore_id` param. + static constexpr int kDefaultRestoreId = 0; + // Callback that receives the result of a user being warned about closing a // browser window (for example, if closing the window would interrupt a // download). The parameter is whether the close should proceed. @@ -250,7 +253,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) // The id from the restore data to restore the browser window. - int32_t restore_id = 0; + int32_t restore_id = kDefaultRestoreId; #endif bool is_focus_mode = false;
diff --git a/chrome/browser/ui/caption_bubble_controller.h b/chrome/browser/ui/caption_bubble_controller.h index 183ffcc..645e754 100644 --- a/chrome/browser/ui/caption_bubble_controller.h +++ b/chrome/browser/ui/caption_bubble_controller.h
@@ -13,7 +13,7 @@ namespace captions { -class CaptionHostImpl; +class LiveCaptionSpeechRecognitionHost; /////////////////////////////////////////////////////////////////////////////// // Caption Bubble Controller @@ -37,14 +37,16 @@ // the transcription result was set on the caption bubble successfully. // Transcriptions will halt if this returns false. virtual bool OnTranscription( - CaptionHostImpl* caption_host_impl, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result) = 0; // Called when the speech service has an error. - virtual void OnError(CaptionHostImpl* caption_host_impl) = 0; + virtual void OnError(LiveCaptionSpeechRecognitionHost* + live_caption_speech_recognition_host) = 0; // Called when the audio stream has ended. - virtual void OnAudioStreamEnd(CaptionHostImpl* caption_host_impl) = 0; + virtual void OnAudioStreamEnd(LiveCaptionSpeechRecognitionHost* + live_caption_speech_recognition_host) = 0; // Called when the caption style changes. virtual void UpdateCaptionStyle(
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc index 1485a7c..f3fba4c 100644 --- a/chrome/browser/ui/page_info/page_info_unittest.cc +++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -631,16 +631,11 @@ // Define some dummy constants for Android-only resources. #if !defined(OS_ANDROID) -#define IDR_PAGEINFO_WARNING_MINOR 0 #define IDR_PAGEINFO_BAD 0 #define IDR_PAGEINFO_GOOD 0 #endif TEST_F(PageInfoTest, InsecureContent) { -#if defined(OS_ANDROID) - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature(page_info::kPageInfoV2); -#endif struct TestCase { security_state::SecurityLevel security_level; net::CertStatus cert_status; @@ -661,7 +656,7 @@ false /* ran_content_with_cert_errors */, false /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Passive mixed content with a nonsecure form. The nonsecure form is the // more severe problem. {security_state::NONE, 0, false /* ran_mixed_content */, @@ -669,21 +664,21 @@ false /* ran_content_with_cert_errors */, false /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Only nonsecure form. {security_state::NONE, 0, false /* ran_mixed_content */, false /* displayed_mixed_content */, true, false /* ran_content_with_cert_errors */, false /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Passive mixed content with a cert error on the main resource. {security_state::DANGEROUS, net::CERT_STATUS_DATE_INVALID, false /* ran_mixed_content */, true /* displayed_mixed_content */, false, false /* ran_content_with_cert_errors */, false /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_ERROR, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_ERROR, IDR_PAGEINFO_BAD}, // Active and passive mixed content. {security_state::DANGEROUS, 0, true /* ran_mixed_content */, true /* displayed_mixed_content */, false, @@ -727,7 +722,7 @@ false /* ran_content_with_cert_errors */, true /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Passive subresources with cert errors, with a cert error on the // main resource also. In this case, the subresources with // certificate errors are ignored: if the main resource had a cert @@ -774,13 +769,7 @@ true /* displayed_content_with_cert_errors */, false, false /* ran_mixed_content */, true /* displayed_mixed_content */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, - // Passive mixed content and subresources with cert errors. - {security_state::NONE, 0, false /* ran_content_with_cert_errors */, - true /* displayed_content_with_cert_errors */, false, - false /* ran_mixed_content */, true /* displayed_mixed_content */, - PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Passive mixed content, a nonsecure form, and subresources with cert // errors. {security_state::NONE, 0, false /* ran_mixed_content */, @@ -788,7 +777,7 @@ false /* ran_content_with_cert_errors */, true /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION, - PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_CERT, IDR_PAGEINFO_BAD}, // Passive mixed content and active subresources with cert errors. {security_state::DANGEROUS, 0, false /* ran_mixed_content */, true /* displayed_mixed_content */, false, @@ -810,7 +799,7 @@ true /* ran_content_with_cert_errors */, false /* displayed_content_with_cert_errors */, PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE, - PageInfo::SITE_IDENTITY_STATUS_ERROR, IDR_PAGEINFO_WARNING_MINOR}, + PageInfo::SITE_IDENTITY_STATUS_ERROR, IDR_PAGEINFO_BAD}, }; for (const auto& test : kTestCases) { @@ -934,7 +923,7 @@ EXPECT_EQ(PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM, page_info()->site_identity_status()); #if defined(OS_ANDROID) - EXPECT_EQ(IDR_PAGEINFO_BAD_V2, + EXPECT_EQ(IDR_PAGEINFO_BAD, PageInfoUI::GetIdentityIconID(page_info()->site_identity_status())); #endif }
diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc index b633d60..bd42e9fe 100644 --- a/chrome/browser/ui/prefs/pref_watcher.cc +++ b/chrome/browser/ui/prefs/pref_watcher.cc
@@ -15,6 +15,7 @@ #include "chrome/common/pref_names.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/language/core/browser/pref_names.h" +#include "components/live_caption/pref_names.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc index acfcad9..5dabb0a 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc
@@ -10,7 +10,7 @@ #include "base/bind.h" #include "chrome/browser/accessibility/caption_controller.h" #include "chrome/browser/accessibility/caption_controller_factory.h" -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -46,11 +46,11 @@ } bool CaptionBubbleControllerViews::OnTranscription( - CaptionHostImpl* caption_host_impl, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result) { if (!caption_bubble_) return false; - SetActiveModel(caption_host_impl); + SetActiveModel(live_caption_speech_recognition_host); if (active_model_->IsClosed()) return false; @@ -69,27 +69,28 @@ return true; } -void CaptionBubbleControllerViews::OnError(CaptionHostImpl* caption_host_impl) { +void CaptionBubbleControllerViews::OnError( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_) return; - SetActiveModel(caption_host_impl); + SetActiveModel(live_caption_speech_recognition_host); if (active_model_->IsClosed()) return; active_model_->OnError(); } void CaptionBubbleControllerViews::OnAudioStreamEnd( - CaptionHostImpl* caption_host_impl) { + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { if (!caption_bubble_) return; CaptionBubbleModel* caption_bubble_model = - caption_bubble_models_[caption_host_impl].get(); + caption_bubble_models_[live_caption_speech_recognition_host].get(); if (active_model_ == caption_bubble_model) { active_model_ = nullptr; caption_bubble_->SetModel(nullptr); } - caption_bubble_models_.erase(caption_host_impl); + caption_bubble_models_.erase(live_caption_speech_recognition_host); } void CaptionBubbleControllerViews::UpdateCaptionStyle( @@ -98,9 +99,10 @@ } void CaptionBubbleControllerViews::SetActiveModel( - CaptionHostImpl* caption_host_impl) { - if (!caption_bubble_models_.count(caption_host_impl)) { - content::WebContents* web_contents = caption_host_impl->GetWebContents(); + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { + if (!caption_bubble_models_.count(live_caption_speech_recognition_host)) { + content::WebContents* web_contents = + live_caption_speech_recognition_host->GetWebContents(); views::Widget* context_widget = web_contents ? views::Widget::GetTopLevelWidgetForNativeView( web_contents->GetNativeView()) @@ -109,7 +111,7 @@ if (context_widget) context_bounds = context_widget->GetClientAreaBoundsInScreen(); caption_bubble_models_.emplace( - caption_host_impl, + live_caption_speech_recognition_host, std::make_unique<CaptionBubbleModel>( context_bounds, base::BindRepeating(&CaptionBubbleControllerViews::ActivateContext, @@ -117,7 +119,7 @@ } CaptionBubbleModel* caption_bubble_model = - caption_bubble_models_[caption_host_impl].get(); + caption_bubble_models_[live_caption_speech_recognition_host].get(); if (active_model_ != caption_bubble_model) { active_model_ = caption_bubble_model; caption_bubble_->SetModel(active_model_);
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h index 62e9239..061bb2a2 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h
@@ -41,14 +41,16 @@ // the transcription result was set on the caption bubble successfully. // Transcriptions will halt if this returns false. bool OnTranscription( - CaptionHostImpl* caption_host_impl, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, const media::mojom::SpeechRecognitionResultPtr& result) override; // Called when the speech service has an error. - void OnError(CaptionHostImpl* caption_host_impl) override; + void OnError(LiveCaptionSpeechRecognitionHost* + live_caption_speech_recognition_host) override; // Called when the audio stream has ended. - void OnAudioStreamEnd(CaptionHostImpl* caption_host_impl) override; + void OnAudioStreamEnd(LiveCaptionSpeechRecognitionHost* + live_caption_speech_recognition_host) override; // Called when the caption style changes. void UpdateCaptionStyle( @@ -64,7 +66,8 @@ // Sets the active CaptionBubbleModel to the one corresponding to the given // media player id, and creates a new CaptionBubbleModel if one does not // already exist. - void SetActiveModel(CaptionHostImpl* caption_host_impl); + void SetActiveModel( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host); // A callback passed to the CaptionBubbleModel which is called when the // BackToTab button is clicked in the CaptionBubble. @@ -82,7 +85,8 @@ // A map of media player ids and their corresponding CaptionBubbleModel. New // entries are added to this map when a previously unseen media player id is // received. - std::unordered_map<CaptionHostImpl*, std::unique_ptr<CaptionBubbleModel>> + std::unordered_map<LiveCaptionSpeechRecognitionHost*, + std::unique_ptr<CaptionBubbleModel>> caption_bubble_models_; }; } // namespace captions
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc index 45dadd3..20e9436 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -10,7 +10,7 @@ #include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" -#include "chrome/browser/accessibility/caption_host_impl.h" +#include "chrome/browser/accessibility/live_caption_speech_recognition_host.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -53,11 +53,12 @@ return controller_.get(); } - CaptionHostImpl* GetCaptionHostImpl() { - if (!caption_host_impl_) - caption_host_impl_ = std::make_unique<CaptionHostImpl>( + LiveCaptionSpeechRecognitionHost* GetLiveCaptionSpeechRecognitionHost() { + if (!live_caption_speech_recognition_host_) + live_caption_speech_recognition_host_ = std::make_unique< + LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame()); - return caption_host_impl_.get(); + return live_caption_speech_recognition_host_.get(); } CaptionBubble* GetBubble() { @@ -140,35 +141,38 @@ } bool OnPartialTranscription(std::string text) { - return OnPartialTranscription(text, GetCaptionHostImpl()); + return OnPartialTranscription(text, GetLiveCaptionSpeechRecognitionHost()); } - bool OnPartialTranscription(std::string text, - CaptionHostImpl* caption_host_impl) { + bool OnPartialTranscription( + std::string text, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { return GetController()->OnTranscription( - caption_host_impl, + live_caption_speech_recognition_host, media::mojom::SpeechRecognitionResult::New(text, false)); } bool OnFinalTranscription(std::string text) { - return OnFinalTranscription(text, GetCaptionHostImpl()); + return OnFinalTranscription(text, GetLiveCaptionSpeechRecognitionHost()); } - bool OnFinalTranscription(std::string text, - CaptionHostImpl* caption_host_impl) { + bool OnFinalTranscription( + std::string text, + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { return GetController()->OnTranscription( - caption_host_impl, + live_caption_speech_recognition_host, media::mojom::SpeechRecognitionResult::New(text, true)); } - void OnError() { OnError(GetCaptionHostImpl()); } + void OnError() { OnError(GetLiveCaptionSpeechRecognitionHost()); } - void OnError(CaptionHostImpl* caption_host_impl) { - GetController()->OnError(caption_host_impl); + void OnError( + LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { + GetController()->OnError(live_caption_speech_recognition_host); } void OnAudioStreamEnd() { - GetController()->OnAudioStreamEnd(GetCaptionHostImpl()); + GetController()->OnAudioStreamEnd(GetLiveCaptionSpeechRecognitionHost()); } std::vector<ui::AXNodeData> GetAXLinesNodeData() { @@ -199,7 +203,8 @@ private: std::unique_ptr<CaptionBubbleControllerViews> controller_; - std::unique_ptr<CaptionHostImpl> caption_host_impl_; + std::unique_ptr<LiveCaptionSpeechRecognitionHost> + live_caption_speech_recognition_host_; }; IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, ShowsCaptionInBubble) { @@ -342,7 +347,7 @@ OnError(); // The error should not be visible on a different media stream. - auto media_1 = std::make_unique<CaptionHostImpl>( + auto media_1 = std::make_unique<LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetFocusedFrame()); OnPartialTranscription("Elephants are vegetarians.", media_1.get()); EXPECT_TRUE(GetTitle()->GetVisible()); @@ -767,8 +772,9 @@ // This test has two medias. // Media 0 has the text "Polar bears are the largest carnivores on land". // Media 1 has the text "A snail can sleep for two years". - CaptionHostImpl* media_0 = GetCaptionHostImpl(); - auto media_1 = std::make_unique<CaptionHostImpl>( + LiveCaptionSpeechRecognitionHost* media_0 = + GetLiveCaptionSpeechRecognitionHost(); + auto media_1 = std::make_unique<LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetFocusedFrame()); // Send final transcription from media 0. @@ -845,7 +851,7 @@ EXPECT_EQ(7 * line_height, GetLabel()->GetBoundsInScreen().height()); // Switch media. The bubble should remain expanded. - auto media_1 = std::make_unique<CaptionHostImpl>( + auto media_1 = std::make_unique<LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetFocusedFrame()); OnPartialTranscription("Nearly all ants are female.", media_1.get()); EXPECT_TRUE(GetCollapseButton()->GetVisible()); @@ -924,8 +930,9 @@ IN_PROC_BROWSER_TEST_F(CaptionBubbleControllerViewsTest, AccessibleTextChangesWhenMediaChanges) { - CaptionHostImpl* media_0 = GetCaptionHostImpl(); - auto media_1 = std::make_unique<CaptionHostImpl>( + LiveCaptionSpeechRecognitionHost* media_0 = + GetLiveCaptionSpeechRecognitionHost(); + auto media_1 = std::make_unique<LiveCaptionSpeechRecognitionHost>( browser()->tab_strip_model()->GetActiveWebContents()->GetFocusedFrame()); OnPartialTranscription("3 dogs survived the Titanic sinking.", media_0);
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc index 86fbfd924..d3b8ab24 100644 --- a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc +++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
@@ -9,6 +9,8 @@ #include "chrome/browser/ui/views/autofill/address_editor_view.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/views/layout/fill_layout.h" namespace autofill { @@ -39,6 +41,9 @@ SetTitle(controller_->GetWindowTitle()); SetButtonLabel(ui::DIALOG_BUTTON_OK, controller_->GetOkButtonLabel()); + SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_CANCEL_BUTTON_LABEL)); } EditAddressProfileView::~EditAddressProfileView() = default;
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_icon_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_icon_view.cc index ebad3aa..93b2b52 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_icon_view.cc +++ b/chrome/browser/ui/views/autofill/save_address_profile_icon_view.cc
@@ -32,9 +32,6 @@ } void SaveAddressProfileIconView::UpdateImpl() { - if (!GetWebContents()) - return; - SaveAddressProfileIconController* controller = GetController(); bool command_enabled = SetCommandEnabled(controller && controller->IsBubbleActive()); @@ -43,8 +40,10 @@ std::u16string SaveAddressProfileIconView::GetTextForTooltipAndAccessibleName() const { - // TODO(crbug.com/1167060): Update upon having final mocks. - return u"Save Address"; + SaveAddressProfileIconController* controller = GetController(); + if (!controller) + return std::u16string(); + return controller->GetPageActionIconTootip(); } void SaveAddressProfileIconView::OnExecuting(
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_view.cc index f7d0472..1546720 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_view.cc +++ b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
@@ -17,7 +17,9 @@ #include "components/autofill/core/browser/data_model/autofill_profile.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_combobox_model.h" #include "ui/gfx/color_utils.h" #include "ui/views/controls/button/image_button.h" @@ -222,6 +224,14 @@ base::Unretained(controller_), AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined)); + SetTitle(controller_->GetWindowTitle()); + SetButtonLabel(ui::DIALOG_BUTTON_OK, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_OK_BUTTON_LABEL)); + SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL)); + SetLayoutManager(std::make_unique<views::FlexLayout>()) ->SetOrientation(views::LayoutOrientation::kHorizontal) .SetCrossAxisAlignment(views::LayoutAlignment::kStart) @@ -235,14 +245,15 @@ views::MinimumFlexSizeRule::kPreferredSnapToMinimum, views::MaximumFlexSizeRule::kUnbounded)); - // TODO(crbug.com/1167060): Update icons upon having final mocks edit_button_ = AddChildView(views::CreateVectorImageButtonWithNativeTheme( base::BindRepeating( &SaveUpdateAddressProfileBubbleController::OnEditButtonClicked, base::Unretained(controller_)), vector_icons::kEditIcon, kIconSize)); - // TODO(crbug.com/1167060): Use internationalized string. - edit_button_->SetAccessibleName(u"Edit Address"); + edit_button_->SetAccessibleName(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_EDIT_BUTTON_TOOLTIP)); + edit_button_->SetTooltipText(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_EDIT_BUTTON_TOOLTIP)); address_components_view_ ->SetLayoutManager(std::make_unique<views::FlexLayout>()) @@ -305,10 +316,6 @@ return true; } -std::u16string SaveAddressProfileView::GetWindowTitle() const { - return controller_->GetWindowTitle(); -} - void SaveAddressProfileView::WindowClosing() { if (controller_) { controller_->OnBubbleClosed(); @@ -334,7 +341,6 @@ } void SaveAddressProfileView::AddedToWidget() { - // TODO(crbug.com/1167060): Update upon having final mocks. // Set the header image. ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); auto image_view = std::make_unique<ThemeTrackingNonAccessibleImageView>(
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.h b/chrome/browser/ui/views/autofill/save_address_profile_view.h index e4d6567..653ccdf 100644 --- a/chrome/browser/ui/views/autofill/save_address_profile_view.h +++ b/chrome/browser/ui/views/autofill/save_address_profile_view.h
@@ -36,7 +36,6 @@ // views::WidgetDelegate: bool ShouldShowCloseButton() const override; - std::u16string GetWindowTitle() const override; void WindowClosing() override; void Show(DisplayReason reason);
diff --git a/chrome/browser/ui/views/autofill/update_address_profile_view.cc b/chrome/browser/ui/views/autofill/update_address_profile_view.cc index 238319d..f05e2fb 100644 --- a/chrome/browser/ui/views/autofill/update_address_profile_view.cc +++ b/chrome/browser/ui/views/autofill/update_address_profile_view.cc
@@ -12,7 +12,9 @@ #include "components/autofill/core/browser/autofill_address_util.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" @@ -29,13 +31,6 @@ constexpr int kIconSize = 16; constexpr int kValuesLabelWidth = 190; -int AddressDetailsIconSize() { - // Use the line height of the body small text. This allows the icons to adapt - // if the user changes the font size. - return views::style::GetLineHeight(views::style::CONTEXT_LABEL, - views::style::STYLE_PRIMARY); -} - const gfx::VectorIcon& GetVectorIconForType(ServerFieldType type) { switch (type) { case NAME_FULL_WITH_HONORIFIC_PREFIX: @@ -92,9 +87,8 @@ views::DISTANCE_RELATED_LABEL_HORIZONTAL))); auto icon_view = std::make_unique<views::ImageView>(); - icon_view->SetImage( - ui::ImageModel::FromVectorIcon(GetVectorIconForType(diff_entry.type), - icon_color, AddressDetailsIconSize())); + icon_view->SetImage(ui::ImageModel::FromVectorIcon( + GetVectorIconForType(diff_entry.type), icon_color, kIconSize)); value_row->AddChildView(std::move(icon_view)); auto label_view = @@ -117,11 +111,13 @@ layout->StartRow(/*vertical_resize=*/views::GridLayout::kFixedSize, kColumnSetId); - // TODO(crbug.com/1167060): Use internationalized string. if (show_row_label) { std::unique_ptr<views::Label> label(new views::Label( - are_new_values ? u"New" : u"Old", views::style::CONTEXT_LABEL, - views::style::STYLE_SECONDARY)); + l10n_util::GetStringUTF16( + are_new_values + ? IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_NEW_VALUES_SECTION_LABEL + : IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_OLD_VALUES_SECTION_LABEL), + views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY)); layout->AddView(std::move(label), /*col_span=*/1, /*row_span=*/1, /*h_align=*/views::GridLayout::LEADING, /*v_align=*/views::GridLayout::LEADING); @@ -139,8 +135,11 @@ views::CreateVectorImageButtonWithNativeTheme( std::move(edit_button_callback), vector_icons::kEditIcon, kIconSize); - // TODO(crbug.com/1167060): Use internationalized string. - edit_button->SetAccessibleName(u"Edit Address"); + + edit_button->SetAccessibleName(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_EDIT_BUTTON_TOOLTIP)); + edit_button->SetTooltipText(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_EDIT_BUTTON_TOOLTIP)); layout->AddView(std::move(edit_button), /*col_span=*/1, /*row_span=*/1, /*h_align=*/views::GridLayout::LEADING, /*v_align=*/views::GridLayout::LEADING); @@ -188,6 +187,14 @@ base::Unretained(controller_), AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined)); + SetTitle(controller_->GetWindowTitle()); + SetButtonLabel(ui::DIALOG_BUTTON_OK, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_OK_BUTTON_LABEL)); + SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL)); + SetLayoutManager(std::make_unique<views::FlexLayout>()) ->SetOrientation(views::LayoutOrientation::kVertical) .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc index d8d7627..fbfb79a 100644 --- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc +++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
@@ -187,7 +187,8 @@ action_taken_ = SafetyTipInteraction::kDismissWithClose; break; case views::Widget::ClosedReason::kCancelButtonClicked: - NOTREACHED(); + // I don't know why, but ESC sometimes generates kCancelButtonClicked. + action_taken_ = SafetyTipInteraction::kDismissWithEsc; break; } std::move(close_callback_).Run(action_taken_);
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc index fb794bc..6852bd7 100644 --- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -260,6 +260,8 @@ switch (ui_status()) { case UIStatus::kDisabled: disabled_features.push_back(security_state::features::kSafetyTipUI); + disabled_features.push_back( + lookalikes::features::kDetectTargetEmbeddingLookalikes); break; case UIStatus::kEnabledWithDefaultFeatures: enabled_features.emplace_back(security_state::features::kSafetyTipUI, @@ -271,8 +273,7 @@ base::FieldTrialParams({{"suspicioussites", "true"}, {"topsites", "false"}, {"editdistance", "false"}, - {"editdistance_siteengagement", "false"}, - {"targetembedding", "false"}})); + {"editdistance_siteengagement", "false"}})); break; case UIStatus::kEnabledWithAllFeatures: enabled_features.emplace_back( @@ -280,8 +281,7 @@ base::FieldTrialParams({{"suspicioussites", "true"}, {"topsites", "true"}, {"editdistance", "true"}, - {"editdistance_siteengagement", "true"}, - {"targetembedding", "true"}})); + {"editdistance_siteengagement", "true"}})); enabled_features.emplace_back( lookalikes::features::kDetectTargetEmbeddingLookalikes, base::FieldTrialParams()); @@ -606,7 +606,7 @@ browser(), security_state::SafetyTipStatus::kBadReputation, GURL())); // ...but suppressed by the allowlist. - reputation::SetSafetyTipAllowlistPatterns({"site1.com/"}, {}); + reputation::SetSafetyTipAllowlistPatterns({"site1.com/"}, {}, {}); NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); EXPECT_FALSE(IsUIShowing()); ASSERT_NO_FATAL_FAILURE(CheckPageInfoDoesNotShowSafetyTipInfo(browser())); @@ -874,7 +874,7 @@ EXPECT_TRUE(IsUIShowingOrAllFeaturesEnabled()); // ...but suppressed by the allowlist. - reputation::SetSafetyTipAllowlistPatterns({"xn--googl-fsa.sk/"}, {}); + reputation::SetSafetyTipAllowlistPatterns({"xn--googl-fsa.sk/"}, {}, {}); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); EXPECT_FALSE(IsUIShowing()); @@ -891,7 +891,7 @@ // This domain is one edit distance from one of a top 500 domain. const GURL kNavigatedUrl = GetURL("gooogle.com"); - reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}); + reputation::SetSafetyTipAllowlistPatterns({}, {"google\\.com"}, {}); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); @@ -904,13 +904,36 @@ // distance when enabled, and not otherwise. IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, TriggersOnEditDistance) { - // This domain is an edit distance of one from the top 500. + // This domain is an edit distance from google.com. const GURL kNavigatedUrl = GetURL("goooglé.com"); + const GURL kTargetUrl = GetURL("google.com"); SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + SetEngagementScore(browser(), kTargetUrl, kHighEngagement); NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); EXPECT_EQ(IsUIShowing(), AreLookalikeWarningsEnabled()); } +// Tests that Safety Tips trigger on lookalike domains with tail embedding when +// enabled, and not otherwise. +IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, + TriggersOnTailEmbedding) { + // Tail-embedding has the canonical domain at the very end of the lookalike. + const GURL kNavigatedUrl = GetURL("accounts-google.com"); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_TRUE(IsUIShowingOrDisabled()); +} + +// Tests that Safety Tips don't trigger on lookalike domains with non-tail +// target embedding. +IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest, + DoesntTriggersOnGenericTargetEmbedding) { + const GURL kNavigatedUrl = GetURL("google.com.evil.com"); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_FALSE(IsUIShowing()); +} + // Tests that the SafetyTipShown histogram triggers correctly. // Flaky on all platforms: https://crbug.com/1139955 IN_PROC_BROWSER_TEST_P(SafetyTipPageInfoBubbleViewBrowserTest,
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 66eb538..5821f25d 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -2116,6 +2116,12 @@ create_params.user_gesture = true; create_params.in_tab_dragging = true; create_params.initial_bounds = new_bounds; +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Do not copy attached window's restore id as this will cause Full Restore to + // restore the newly created browser using the original browser's stored data. + // See crbug.com/1208923 for details. + create_params.restore_id = Browser::kDefaultRestoreId; +#endif // Do not copy attached window's show state as the attached window might be a // maximized or fullscreen window and we do not want the newly created browser // window is a maximized or fullscreen window since it will prevent window
diff --git a/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc b/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc index 07567da..d9c8f77 100644 --- a/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc +++ b/chrome/browser/ui/views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc
@@ -86,11 +86,11 @@ keep_alive_(std::move(keep_alive)), close_callback_(std::move(close_callback)) { SetDefaultButton(ui::DIALOG_BUTTON_CANCEL); - SetModalType(ui::MODAL_TYPE_WINDOW); + SetModalType(ui::MODAL_TYPE_NONE); std::u16string title = l10n_util::GetStringUTF16( IDS_PROTOCOL_HANDLER_INTENT_PICKER_SINGLE_TITLE); SetTitle(title); - SetShowCloseButton(false); + SetShowCloseButton(true); SetButtonLabel(ui::DIALOG_BUTTON_OK, l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/webid/account_selection_view.h b/chrome/browser/ui/webid/account_selection_view.h index 70f9aa6..1851d53 100644 --- a/chrome/browser/ui/webid/account_selection_view.h +++ b/chrome/browser/ui/webid/account_selection_view.h
@@ -37,10 +37,12 @@ virtual ~AccountSelectionView() = default; // Instructs the view to show the provided |accounts| to the user. - // |url| is the current origin. + // |rp_url| is the current origin and |idp_url| is the IdP origin. // After user interaction either OnAccountSelected() or OnDismiss() gets // invoked. - virtual void Show(const GURL& url, base::span<const Account> accounts) = 0; + virtual void Show(const GURL& rp_url, + const GURL& idp_url, + base::span<const Account> accounts) = 0; protected: Delegate* delegate_ = nullptr;
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.cc b/chrome/browser/ui/webid/identity_dialog_controller.cc index c04163c..e52290a 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller.cc
@@ -95,20 +95,22 @@ void IdentityDialogController::ShowAccountsDialog( content::WebContents* rp_web_contents, content::WebContents* idp_web_contents, - const GURL& idp_signin_url, + const GURL& idp_url, AccountList accounts, AccountSelectionCallback on_selected) { + // IDP scheme is expected to always be `https://`. + CHECK(idp_url.SchemeIs(url::kHttpsScheme)); #if !defined(OS_ANDROID) std::move(on_selected).Run(accounts[0].sub); #else rp_web_contents_ = rp_web_contents; on_account_selection_ = std::move(on_selected); - const GURL& url = rp_web_contents_->GetLastCommittedURL(); + const GURL& rp_url = rp_web_contents_->GetLastCommittedURL(); if (!account_view_) account_view_ = AccountSelectionView::Create(this); - account_view_->Show(url, accounts); + account_view_->Show(rp_url, idp_url, accounts); #endif }
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.h b/chrome/browser/ui/webid/identity_dialog_controller.h index e67d30e..64d6c66 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.h +++ b/chrome/browser/ui/webid/identity_dialog_controller.h
@@ -48,7 +48,7 @@ void ShowAccountsDialog(content::WebContents* rp_web_contents, content::WebContents* idp_web_contents, - const GURL& idp_signin_url, + const GURL& idp_url, AccountList accounts, AccountSelectionCallback on_selected) override;
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index bd74ce6..bf86688 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -824,7 +824,7 @@ !profile->IsOffTheRecord()) { return &NewWebUI<nearby_share::NearbyShareDialogUI>; } - if (url.host_piece() == chrome::kChromeUIProjectorHost) + if (url.host_piece() == chrome::kChromeUIProjectorSelfieCamHost) return &NewWebUI<chromeos::ProjectorUI>; if (url.host_piece() == chrome::kChromeUISetTimeHost) return &NewWebUI<chromeos::SetTimeUI>;
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc index 10310760..2073bbf 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -11,6 +11,7 @@ #include "base/values.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/grit/generated_resources.h" +#include "chrome/grit/oobe_resources.h" #include "components/login/localized_values_builder.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_ui_data_source.h" @@ -83,13 +84,20 @@ {"confirmationCodeError", IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_ERROR}, {"confirmationCodeLoading", - IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_LOADING}}; // namespace + IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_LOADING}, + {"verifyingActivationCode", + IDS_CELLULAR_SETUP_ESIM_PAGE_VERIFYING_ACTIVATION_CODE}}; struct NamedBoolean { const char* name; bool value; }; +struct NamedResourceId { + const char* name; + int value; +}; + const std::vector<const NamedBoolean>& GetBooleanValues() { static const base::NoDestructor<std::vector<const NamedBoolean>> named_bools( {{"updatedCellularActivationUi", @@ -100,6 +108,12 @@ return *named_bools; } +const std::vector<const NamedResourceId>& GetResourceIdValues() { + static const base::NoDestructor<std::vector<const NamedResourceId>> + named_resource_ids({{"spinner.json", IDR_LOGIN_SPINNER_ANIMATION}}); + return *named_resource_ids; +} + } // namespace void AddLocalizedStrings(content::WebUIDataSource* html_source) { @@ -114,11 +128,17 @@ void AddNonStringLoadTimeData(content::WebUIDataSource* html_source) { for (const auto& entry : GetBooleanValues()) html_source->AddBoolean(entry.name, entry.value); + + for (const auto& entry : GetResourceIdValues()) + html_source->AddResourcePath(entry.name, entry.value); } void AddNonStringLoadTimeDataToDict(base::DictionaryValue* dict) { for (const auto& entry : GetBooleanValues()) dict->SetBoolean(entry.name, entry.value); + + for (const auto& entry : GetResourceIdValues()) + dict->SetInteger(entry.name, entry.value); } } // namespace cellular_setup
diff --git a/chrome/browser/ui/webui/chromeos/projector/projector_ui.cc b/chrome/browser/ui/webui/chromeos/projector/projector_ui.cc index 110edb2..429862a 100644 --- a/chrome/browser/ui/webui/chromeos/projector/projector_ui.cc +++ b/chrome/browser/ui/webui/chromeos/projector/projector_ui.cc
@@ -6,7 +6,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/webui_util.h" -#include "chrome/common/url_constants.h" +#include "chrome/common/webui_url_constants.h" #include "chromeos/projector/grit/projector_resources.h" #include "chromeos/projector/grit/projector_resources_map.h" #include "content/public/browser/web_ui_data_source.h" @@ -17,7 +17,7 @@ content::WebUIDataSource* CreateProjectorHTMLSource() { content::WebUIDataSource* source = - content::WebUIDataSource::Create(chrome::kChromeUIProjectorHost); + content::WebUIDataSource::Create(chrome::kChromeUIProjectorSelfieCamHost); webui::SetupWebUIDataSource( source, base::make_span(kProjectorResources, kProjectorResourcesSize), @@ -27,11 +27,14 @@ } // namespace -ProjectorUI::ProjectorUI(content::WebUI* web_ui) : WebUIController(web_ui) { +ProjectorUI::ProjectorUI(content::WebUI* web_ui) + : MojoBubbleWebUIController(web_ui) { Profile* profile = Profile::FromWebUI(web_ui); content::WebUIDataSource::Add(profile, CreateProjectorHTMLSource()); } ProjectorUI::~ProjectorUI() = default; +WEB_UI_CONTROLLER_TYPE_IMPL(ProjectorUI) + } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/projector/projector_ui.h b/chrome/browser/ui/webui/chromeos/projector/projector_ui.h index 367d28f..283860f8 100644 --- a/chrome/browser/ui/webui/chromeos/projector/projector_ui.h +++ b/chrome/browser/ui/webui/chromeos/projector/projector_ui.h
@@ -6,16 +6,20 @@ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_PROJECTOR_PROJECTOR_UI_H_ #include "content/public/browser/web_ui_controller.h" +#include "ui/webui/mojo_bubble_web_ui_controller.h" namespace chromeos { // The implementation for the Projector Selfie Cam WebUI. -class ProjectorUI : public content::WebUIController { +class ProjectorUI : public ui::MojoBubbleWebUIController { public: explicit ProjectorUI(content::WebUI* web_ui); ~ProjectorUI() override; ProjectorUI(const ProjectorUI&) = delete; ProjectorUI& operator=(const ProjectorUI&) = delete; + + private: + WEB_UI_CONTROLLER_TYPE_DECL(); }; } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.cc b/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.cc new file mode 100644 index 0000000..597174a --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.cc
@@ -0,0 +1,207 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.h" + +#include <memory> + +#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/views/bubble/webui_bubble_dialog_view.h" +#include "chrome/browser/ui/webui/chromeos/projector/projector_ui.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/bubble/bubble_border.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/controls/native/native_view_host.h" +#include "ui/views/controls/webview/webview.h" + +namespace chromeos { + +namespace { + +constexpr int kCornerRadiusDip = 80; + +constexpr gfx::Size kPreferredSize(2 * kCornerRadiusDip, 2 * kCornerRadiusDip); + +// Makes the selfie cam draggable. +class SelfieCamBubbleFrameView : public views::BubbleFrameView { + public: + SelfieCamBubbleFrameView() + : views::BubbleFrameView(gfx::Insets(), gfx::Insets()) { + auto border = std::make_unique<views::BubbleBorder>( + views::BubbleBorder::FLOAT, views::BubbleBorder::DIALOG_SHADOW, + gfx::kPlaceholderColor); + // Needed to make the selfie cam round. + border->SetCornerRadius(kCornerRadiusDip); + views::BubbleFrameView::SetBubbleBorder(std::move(border)); + } + + ~SelfieCamBubbleFrameView() override = default; + SelfieCamBubbleFrameView(const SelfieCamBubbleFrameView&) = delete; + SelfieCamBubbleFrameView& operator=(const SelfieCamBubbleFrameView&) = delete; + + // Needed to make the selfie cam draggable everywhere within its bounds. + int NonClientHitTest(const gfx::Point& point) override { + // Outside of the window bounds, do nothing. + if (!bounds().Contains(point)) + return HTNOWHERE; + + // Ensure it's within the BubbleFrameView. This takes into account the + // rounded corners and drop shadow of the BubbleBorder. + int hit = views::BubbleFrameView::NonClientHitTest(point); + + // After BubbleFrameView::NonClientHitTest processes the bubble-specific + // hits such as the rounded corners, it checks hits to the bubble's client + // view. Any hits to ClientFrameView::NonClientHitTest return HTCLIENT or + // HTNOWHERE. Override these to return HTCAPTION in order to make the + // entire widget draggable. + return (hit == HTCLIENT || hit == HTNOWHERE) ? HTCAPTION : hit; + } +}; + +// Dialog that displays the selfie cam for including the user's face in +// Projector screen recordings. +class SelfieCamBubbleDialogView : public WebUIBubbleDialogView { + public: + SelfieCamBubbleDialogView( + std::unique_ptr<BubbleContentsWrapper> contents_wrapper) + : WebUIBubbleDialogView(/*anchor_view=*/nullptr, contents_wrapper.get()), + contents_wrapper_(std::move(contents_wrapper)) { + set_has_parent(false); + set_close_on_deactivate(false); + } + ~SelfieCamBubbleDialogView() override = default; + + // views::BubbleDialogDelegateView: + // Opens the selfie cam in the middle of the screen initially. + // TODO(crbug/1199396): Consider if the selfie cam should appear somewhere + // else by default initially, such as the bottom right of the screen. + gfx::Rect GetBubbleBounds() override { + // Bubble bounds are what the computed bubble bounds would be, taking into + // account the current bubble size. + gfx::Rect bubble_bounds = + views::BubbleDialogDelegateView::GetBubbleBounds(); + // Widget bounds are where the bubble currently is in space. + gfx::Rect widget_bounds = GetWidget()->GetWindowBoundsInScreen(); + // Use the widget x and y to keep the bubble oriented at its current + // location, and use the bubble width and height to set the correct bubble + // size. + return gfx::Rect(widget_bounds.x(), widget_bounds.y(), + bubble_bounds.width(), bubble_bounds.height()); + } + + // views::BubbleDialogDelegateView: + void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, + views::Widget* widget) const override { + params->type = views::Widget::InitParams::TYPE_WINDOW; + // Keeps the selfie cam always on top. + params->z_order = ui::ZOrderLevel::kFloatingWindow; + params->visible_on_all_workspaces = true; + } + + // WidgetDelegate: + std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( + views::Widget* widget) override { + return std::make_unique<SelfieCamBubbleFrameView>(); + } + + // Disallows closing the selfie cam through pressing the escape key because + // the toggle button gets out of sync with the model state. The only way to + // close the selfie cam should be through the toggle off button. + bool OnCloseRequested(views::Widget::ClosedReason close_reason) override { + // Pressing escape maps to kCancelButtonClicked instead of kEscKeyPressed. + return close_reason != views::Widget::ClosedReason::kCancelButtonClicked; + } + + // views::View: + gfx::Size CalculatePreferredSize() const override { return kPreferredSize; } + + private: + std::unique_ptr<BubbleContentsWrapper> contents_wrapper_; +}; + +// Renders the WebUI contents and asks for camera permission so that +// we don't need to prompt the user. +class SelfieCamBubbleContentsWrapper + : public BubbleContentsWrapperT<ProjectorUI> { + public: + SelfieCamBubbleContentsWrapper(const GURL& webui_url, + content::BrowserContext* browser_context, + int task_manager_string_id) + : BubbleContentsWrapperT(webui_url, + browser_context, + task_manager_string_id) {} + + // content::WebContentsDelegate: + void RequestMediaAccessPermission( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + content::MediaResponseCallback callback) override { + MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( + web_contents, request, std::move(callback), /*extension=*/nullptr); + } + + bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host, + const GURL& security_origin, + blink::mojom::MediaStreamType type) override { + return MediaCaptureDevicesDispatcher::GetInstance() + ->CheckMediaAccessPermission(render_frame_host, security_origin, type); + } +}; + +} // namespace + +SelfieCamBubbleManager::SelfieCamBubbleManager() = default; +SelfieCamBubbleManager::~SelfieCamBubbleManager() = default; + +void SelfieCamBubbleManager::Show(Profile* profile) { + if (IsVisible()) + return; + + auto contents_wrapper = std::make_unique<SelfieCamBubbleContentsWrapper>( + GURL(chrome::kChromeUIProjectorSelfieCamURL), profile, + IDS_SELFIE_CAM_TITLE); + // Need to reload the web contents here because the view isn't visible unless + // ShowUI is called from the JS side. By reloading, we trigger the JS to + // eventually call ShowUI(). + contents_wrapper->ReloadWebContents(); + + auto bubble_view = + std::make_unique<SelfieCamBubbleDialogView>(std::move(contents_wrapper)); + + bubble_view_ = bubble_view->GetWeakPtr(); + auto* bubble_widget = + views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view)); + // Needed to set the window.innerWidth and window.innerHeight to the preferred + // size in JavaScript so we can determine the correct camera resolution. + bubble_view_->web_view()->EnableSizingFromWebContents( + /*min_size=*/kPreferredSize, /*max_size=*/kPreferredSize); + // Needed to make the selfie cam round. + bubble_view_->web_view()->holder()->SetCornerRadii( + gfx::RoundedCornersF(kCornerRadiusDip)); + // Needed to make the selfie cam draggable everywhere within its bounds. + bubble_view_->web_view()->holder()->SetHitTestTopInset( + bubble_view_->height()); + bubble_widget->Show(); +} + +void SelfieCamBubbleManager::Close() { + if (!IsVisible()) + return; + + DCHECK(bubble_view_->GetWidget()); + bubble_view_->GetWidget()->CloseNow(); +} + +bool SelfieCamBubbleManager::IsVisible() const { + return bubble_view_ != nullptr; +} + +} // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.h b/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.h new file mode 100644 index 0000000..9e7852d6 --- /dev/null +++ b/chrome/browser/ui/webui/chromeos/projector/selfie_cam_bubble_manager.h
@@ -0,0 +1,33 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_PROJECTOR_SELFIE_CAM_BUBBLE_MANAGER_H_ +#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_PROJECTOR_SELFIE_CAM_BUBBLE_MANAGER_H_ + +#include "base/memory/weak_ptr.h" + +class Profile; +class WebUIBubbleDialogView; + +namespace chromeos { + +// Handles the creation and destruction of the selfie cam WebUI bubble. +class SelfieCamBubbleManager { + public: + SelfieCamBubbleManager(); + SelfieCamBubbleManager(const SelfieCamBubbleManager&) = delete; + SelfieCamBubbleManager& operator=(const SelfieCamBubbleManager&) = delete; + ~SelfieCamBubbleManager(); + + void Show(Profile* profile); + void Close(); + bool IsVisible() const; + + private: + base::WeakPtr<WebUIBubbleDialogView> bubble_view_; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_PROJECTOR_SELFIE_CAM_BUBBLE_MANAGER_H_
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc index b57b84fc..65d94ae 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
@@ -19,6 +19,7 @@ #include "base/values.h" #include "chrome/browser/chromeos/printing/test_cups_printers_manager.h" #include "chrome/browser/chromeos/printing/test_printer_configurer.h" +#include "chrome/browser/printing/print_backend_service_manager.h" #include "chrome/browser/printing/print_backend_service_test_impl.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" @@ -142,24 +143,70 @@ } // namespace -class LocalPrinterHandlerChromeosTest : public testing::Test { +// Base testing class for `LocalPrinterHandlerChromeos`. Contains the base +// logic to allow for using either a local task runner or a service to make +// print backend calls, and to possibly enable fallback when using a service. +// Tests to trigger those different paths can be done by overloading +// `UseService()` and `SupportFallback()`. +class LocalPrinterHandlerChromeosTestBase : public testing::Test { public: - LocalPrinterHandlerChromeosTest() = default; - LocalPrinterHandlerChromeosTest(const LocalPrinterHandlerChromeosTest&) = - delete; - LocalPrinterHandlerChromeosTest& operator=( - const LocalPrinterHandlerChromeosTest&) = delete; - ~LocalPrinterHandlerChromeosTest() override = default; + LocalPrinterHandlerChromeosTestBase() = default; + LocalPrinterHandlerChromeosTestBase( + const LocalPrinterHandlerChromeosTestBase&) = delete; + LocalPrinterHandlerChromeosTestBase& operator=( + const LocalPrinterHandlerChromeosTestBase&) = delete; + ~LocalPrinterHandlerChromeosTestBase() override = default; + + TestPrintBackend* sandboxed_print_backend() { + return sandboxed_test_backend_.get(); + } + TestPrintBackend* unsandboxed_print_backend() { + return unsandboxed_test_backend_.get(); + } + + // Indicate if calls to print backend should be made using a service instead + // of a local task runner. + virtual bool UseService() = 0; + + // Indicate if fallback support for access-denied errors should be included + // when using a service for print backend calls. + virtual bool SupportFallback() = 0; void SetUp() override { - test_backend_ = base::MakeRefCounted<TestPrintBackend>(); - PrintBackend::SetPrintBackendForTesting(test_backend_.get()); + // Choose between running with local test runner or via a service. + feature_list_.InitWithFeatureState(features::kEnableOopPrintDrivers, + UseService()); + + sandboxed_test_backend_ = base::MakeRefCounted<TestPrintBackend>(); ppd_provider_ = base::MakeRefCounted<FakePpdProvider>(); local_printer_handler_ = LocalPrinterHandlerChromeos::CreateForTesting( &profile_, nullptr, &printers_manager_, std::make_unique<chromeos::TestPrinterConfigurer>(), ppd_provider_); + + if (UseService()) { + sandboxed_print_backend_service_ = + PrintBackendServiceTestImpl::LaunchForTesting(sandboxed_test_remote_, + sandboxed_test_backend_, + /*sandboxed=*/true); + + if (SupportFallback()) { + unsandboxed_test_backend_ = base::MakeRefCounted<TestPrintBackend>(); + + unsandboxed_print_backend_service_ = + PrintBackendServiceTestImpl::LaunchForTesting( + unsandboxed_test_remote_, unsandboxed_test_backend_, + /*sandboxed=*/false); + } + } else { + // Use of task runners will call `PrintBackend::CreateInstance()`, which + // needs a test backend registered for it to use. + PrintBackend::SetPrintBackendForTesting(sandboxed_test_backend_.get()); + } } + void TearDown() override { PrintBackendServiceManager::ResetForTesting(); } + + protected: void AddPrinter(const std::string& id, const std::string& display_name, const std::string& description, @@ -170,11 +217,23 @@ auto basic_info = std::make_unique<PrinterBasicInfo>( id, display_name, description, /*printer_status=*/0, is_default, PrinterBasicInfoOptions{}); + + if (SupportFallback()) { + // Need to populate same values into a second print backend. + // For fallback they will always be treated as valid. + auto caps_unsandboxed = + std::make_unique<PrinterSemanticCapsAndDefaults>(*caps); + auto basic_info_unsandboxed = + std::make_unique<PrinterBasicInfo>(*basic_info); + unsandboxed_print_backend()->AddValidPrinter( + id, std::move(caps_unsandboxed), std::move(basic_info_unsandboxed)); + } + if (requires_elevated_permissions) { - test_backend_->AddAccessDeniedPrinter(id); + sandboxed_print_backend()->AddAccessDeniedPrinter(id); } else { - test_backend_->AddValidPrinter(id, std::move(caps), - std::move(basic_info)); + sandboxed_print_backend()->AddValidPrinter(id, std::move(caps), + std::move(basic_info)); } } @@ -182,8 +241,6 @@ TestingProfile& profile() { return profile_; } - scoped_refptr<TestPrintBackend> test_backend() { return test_backend_; } - chromeos::TestCupsPrintersManager& printers_manager() { return printers_manager_; } @@ -197,17 +254,43 @@ content::BrowserTaskEnvironment task_environment_; // Must outlive `printers_manager_`. TestingProfile profile_; - scoped_refptr<TestPrintBackend> test_backend_; + scoped_refptr<TestPrintBackend> sandboxed_test_backend_; + scoped_refptr<TestPrintBackend> unsandboxed_test_backend_; chromeos::TestCupsPrintersManager printers_manager_; scoped_refptr<FakePpdProvider> ppd_provider_; std::unique_ptr<LocalPrinterHandlerChromeos> local_printer_handler_; + + // Support for testing via a service instead of with a local task runner. + base::test::ScopedFeatureList feature_list_; + mojo::Remote<mojom::PrintBackendService> sandboxed_test_remote_; + mojo::Remote<mojom::PrintBackendService> unsandboxed_test_remote_; + std::unique_ptr<PrintBackendServiceTestImpl> sandboxed_print_backend_service_; + std::unique_ptr<PrintBackendServiceTestImpl> + unsandboxed_print_backend_service_; }; -// `LocalPrinterHandlerChromeosProcessScopeTest` performs test which make use -// of the print backend and can utilize that in different process scopes, be -// that in-process via a local task runner or out-of-process through a service. +// Testing class to cover `LocalPrinterHandlerChromeos` handling using a local +// task runner. +class LocalPrinterHandlerChromeosTest + : public LocalPrinterHandlerChromeosTestBase { + public: + LocalPrinterHandlerChromeosTest() = default; + LocalPrinterHandlerChromeosTest(const LocalPrinterHandlerChromeosTest&) = + delete; + LocalPrinterHandlerChromeosTest& operator=( + const LocalPrinterHandlerChromeosTest&) = delete; + ~LocalPrinterHandlerChromeosTest() override = default; + + bool UseService() override { return false; } + bool SupportFallback() override { return false; } +}; + +// Testing class to cover `LocalPrinterHandlerChromeos` handling using either a +// local task runner or a service. Makes no attempt to cover fallback when +// using a service, which is handled separately by +// `LocalPrinterHandlerChromeosFallbackTest` class LocalPrinterHandlerChromeosProcessScopeTest - : public LocalPrinterHandlerChromeosTest, + : public LocalPrinterHandlerChromeosTestBase, public testing::WithParamInterface<bool> { public: LocalPrinterHandlerChromeosProcessScopeTest() = default; @@ -217,22 +300,24 @@ const LocalPrinterHandlerChromeosProcessScopeTest&) = delete; ~LocalPrinterHandlerChromeosProcessScopeTest() override = default; - void SetUp() override { - // Choose between running with local test runner or via a service. - LocalPrinterHandlerChromeosTest::SetUp(); - const bool use_backend_service = GetParam(); - if (use_backend_service) { - feature_list_.InitAndEnableFeature(features::kEnableOopPrintDrivers); - print_backend_service_ = PrintBackendServiceTestImpl::LaunchForTesting( - test_remote_, test_backend()); - } - } + bool UseService() override { return GetParam(); } + bool SupportFallback() override { return false; } +}; - private: - // Support for testing via a service instead of with a local task runner. - base::test::ScopedFeatureList feature_list_; - mojo::Remote<mojom::PrintBackendService> test_remote_; - std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_; +// Testing class to cover `LocalPrinterHandlerChromeos` handling using only a +// service and when fallback could yield different results. +class LocalPrinterHandlerChromeosFallbackTest + : public LocalPrinterHandlerChromeosTestBase { + public: + LocalPrinterHandlerChromeosFallbackTest() = default; + LocalPrinterHandlerChromeosFallbackTest( + const LocalPrinterHandlerChromeosFallbackTest&) = delete; + LocalPrinterHandlerChromeosFallbackTest& operator=( + const LocalPrinterHandlerChromeosFallbackTest&) = delete; + ~LocalPrinterHandlerChromeosFallbackTest() override = default; + + bool UseService() override { return true; } + bool SupportFallback() override { return true; } }; INSTANTIATE_TEST_SUITE_P(All, @@ -315,15 +400,14 @@ AddPrinter("printer1", "saved", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/false); - base::Value fetched_caps; + base::Value fetched_caps("dummy"); local_printer_handler()->StartGetCapability( "printer1", base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); RunUntilIdle(); - ASSERT_TRUE(fetched_caps.is_dict()); - EXPECT_TRUE(fetched_caps.FindKey(kSettingCapabilities)); - EXPECT_TRUE(fetched_caps.FindKey(kPrinter)); + EXPECT_TRUE(fetched_caps.FindDictKey(kSettingCapabilities)); + EXPECT_TRUE(fetched_caps.FindDictKey(kPrinter)); } // Test that printers which have not yet been installed are installed with @@ -340,15 +424,14 @@ AddPrinter("printer1", "discovered", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/false); - base::Value fetched_caps; + base::Value fetched_caps("dummy"); local_printer_handler()->StartGetCapability( "printer1", base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); RunUntilIdle(); - ASSERT_TRUE(fetched_caps.is_dict()); - EXPECT_TRUE(fetched_caps.FindKey(kSettingCapabilities)); - EXPECT_TRUE(fetched_caps.FindKey(kPrinter)); + EXPECT_TRUE(fetched_caps.FindDictKey(kSettingCapabilities)); + EXPECT_TRUE(fetched_caps.FindDictKey(kPrinter)); } // In this test we expect the `StartGetCapability` to bail early because the @@ -379,19 +462,49 @@ AddPrinter("printer1", "saved", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/true); - base::Value fetched_caps; + base::Value fetched_caps("dummy"); local_printer_handler()->StartGetCapability( "printer1", base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); RunUntilIdle(); - ASSERT_TRUE(fetched_caps.is_dict()); - const base::Value* settings = fetched_caps.FindKey(kSettingCapabilities); + const base::Value* settings = fetched_caps.FindDictKey(kSettingCapabilities); ASSERT_TRUE(settings); ASSERT_TRUE(settings->is_dict()); EXPECT_TRUE(settings->DictEmpty()); } +TEST_F(LocalPrinterHandlerChromeosFallbackTest, + StartGetCapabilityElevatedPermissionsSucceeds) { + Printer saved_printer = + CreateTestPrinter("printer1", "saved", "description1"); + printers_manager().AddPrinter(saved_printer, PrinterClass::kSaved); + printers_manager().InstallPrinter("printer1"); + + // Add printer capabilities to `test_backend_`. + AddPrinter("printer1", "saved", "description1", /*is_default=*/true, + /*requires_elevated_permissions=*/true); + + // Note that printer does not initially show as requiring elevated privileges. + EXPECT_FALSE(PrintBackendServiceManager::GetInstance() + .PrinterDriverRequiresElevatedPrivilege("printer1")); + + base::Value fetched_caps("dummy"); + local_printer_handler()->StartGetCapability( + "printer1", base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); + + RunUntilIdle(); + + // Getting capabilities should succeed when fallback is supported. + const base::Value* settings = fetched_caps.FindDictKey(kSettingCapabilities); + ASSERT_TRUE(settings); + EXPECT_TRUE(settings->FindDictKey(kPrinter)); + + // Verify that this printer now shows up as requiring elevated privileges. + EXPECT_TRUE(PrintBackendServiceManager::GetInstance() + .PrinterDriverRequiresElevatedPrivilege("printer1")); +} + TEST_F(LocalPrinterHandlerChromeosTest, GetNativePrinterPolicies) { sync_preferences::TestingPrefServiceSyncable* prefs = profile().GetTestingPrefService();
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc index f79aac5..2602467 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
@@ -89,12 +89,37 @@ void OnDidFetchCapabilities( const std::string& device_name, + bool elevated_privileges, bool has_secure_protocol, PrinterHandler::GetCapabilityCallback callback, mojom::PrinterCapsAndInfoResultPtr printer_caps_and_info) { if (printer_caps_and_info->is_result_code()) { LOG(WARNING) << "Failure fetching printer capabilities for " << device_name << " - error " << printer_caps_and_info->get_result_code(); + + // If we failed because of access denied then we could retry at an elevated + // privilege (if not already elevated). + if (printer_caps_and_info->get_result_code() == + mojom::ResultCode::kAccessDenied && + !elevated_privileges) { + // Register that this printer requires elevated privileges. + PrintBackendServiceManager& service_mgr = + PrintBackendServiceManager::GetInstance(); + service_mgr.SetPrinterDriverRequiresElevatedPrivilege(device_name); + + // Retry the operation which should now happen at a higher privilege + // level. + auto& service = service_mgr.GetService( + g_browser_process->GetApplicationLocale(), device_name); + service->FetchCapabilities( + device_name, + base::BindOnce(&OnDidFetchCapabilities, device_name, + /*elevated_privileges=*/true, has_secure_protocol, + std::move(callback))); + return; + } + + // Unable to fallback, call back without data. std::move(callback).Run(base::Value()); return; } @@ -237,12 +262,16 @@ if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) { VLOG(1) << "Getting printer capabilities via service for " << device_name; - auto& service = PrintBackendServiceManager::GetInstance().GetService( + PrintBackendServiceManager& service_mgr = + PrintBackendServiceManager::GetInstance(); + auto& service = service_mgr.GetService( g_browser_process->GetApplicationLocale(), device_name); service->FetchCapabilities( device_name, - base::BindOnce(&OnDidFetchCapabilities, device_name, - /*has_secure_protocol=*/false, std::move(cb))); + base::BindOnce( + &OnDidFetchCapabilities, device_name, + service_mgr.PrinterDriverRequiresElevatedPrivilege(device_name), + /*has_secure_protocol=*/false, std::move(cb))); } else { VLOG(1) << "Getting printer capabilities in-process for " << device_name; base::PostTaskAndReplyWithResult(
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc index 39657c2..6a941c6e 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default_unittest.cc
@@ -13,6 +13,7 @@ #include "base/memory/scoped_refptr.h" #include "base/strings/string_piece.h" #include "base/values.h" +#include "chrome/browser/printing/print_backend_service_manager.h" #include "chrome/browser/printing/print_backend_service_test_impl.h" #include "chrome/common/printing/printer_capabilities.h" #include "chrome/test/base/testing_profile.h" @@ -65,38 +66,71 @@ } // namespace -class LocalPrinterHandlerDefaultTest : public testing::TestWithParam<bool> { +// Base testing class for `LocalPrinterHandlerDefault`. Contains the base +// logic to allow for using either a local task runner or a service to make +// print backend calls, and to possibly enable fallback when using a service. +// Tests to trigger those different paths can be done by overloading +// `UseService()` and `SupportFallback()`. +class LocalPrinterHandlerDefaultTestBase : public testing::Test { public: - LocalPrinterHandlerDefaultTest() = default; - LocalPrinterHandlerDefaultTest(const LocalPrinterHandlerDefaultTest&) = - delete; - LocalPrinterHandlerDefaultTest& operator=( - const LocalPrinterHandlerDefaultTest&) = delete; - ~LocalPrinterHandlerDefaultTest() override = default; + LocalPrinterHandlerDefaultTestBase() = default; + LocalPrinterHandlerDefaultTestBase( + const LocalPrinterHandlerDefaultTestBase&) = delete; + LocalPrinterHandlerDefaultTestBase& operator=( + const LocalPrinterHandlerDefaultTestBase&) = delete; + ~LocalPrinterHandlerDefaultTestBase() override = default; - TestPrintBackend* print_backend() { return test_backend_.get(); } + TestPrintBackend* sandboxed_print_backend() { + return sandboxed_test_backend_.get(); + } + TestPrintBackend* unsandboxed_print_backend() { + return unsandboxed_test_backend_.get(); + } + + // Indicate if calls to print backend should be made using a service instead + // of a local task runner. + virtual bool UseService() = 0; + + // Indicate if fallback support for access-denied errors should be included + // when using a service for print backend calls. + virtual bool SupportFallback() = 0; void SetUp() override { // Choose between running with local test runner or via a service. - const bool use_backend_service = GetParam(); feature_list_.InitWithFeatureState(features::kEnableOopPrintDrivers, - use_backend_service); + UseService()); TestingProfile::Builder builder; profile_ = builder.Build(); initiator_ = content::WebContents::Create( content::WebContents::CreateParams(profile_.get())); - test_backend_ = base::MakeRefCounted<TestPrintBackend>(); - PrintBackend::SetPrintBackendForTesting(test_backend_.get()); + sandboxed_test_backend_ = base::MakeRefCounted<TestPrintBackend>(); + local_printer_handler_ = std::make_unique<LocalPrinterHandlerDefault>(initiator_.get()); - if (use_backend_service) { - print_backend_service_ = PrintBackendServiceTestImpl::LaunchForTesting( - test_remote_, test_backend_); + if (UseService()) { + sandboxed_print_backend_service_ = + PrintBackendServiceTestImpl::LaunchForTesting(sandboxed_test_remote_, + sandboxed_test_backend_, + /*sandboxed=*/true); + if (SupportFallback()) { + unsandboxed_test_backend_ = base::MakeRefCounted<TestPrintBackend>(); + + unsandboxed_print_backend_service_ = + PrintBackendServiceTestImpl::LaunchForTesting( + unsandboxed_test_remote_, unsandboxed_test_backend_, + /*sandboxed=*/false); + } + } else { + // Use of task runners will call `PrintBackend::CreateInstance()`, which + // needs a test backend registered for it to use. + PrintBackend::SetPrintBackendForTesting(sandboxed_test_backend_.get()); } } + void TearDown() override { PrintBackendServiceManager::ResetForTesting(); } + void AddPrinter(const std::string& id, const std::string& display_name, const std::string& description, @@ -109,11 +143,22 @@ id, display_name, description, /*printer_status=*/0, is_default, PrinterBasicInfoOptions{}); + if (SupportFallback()) { + // Need to populate same values into a second print backend. + // For fallback they will always be treated as valid. + auto caps_unsandboxed = + std::make_unique<PrinterSemanticCapsAndDefaults>(*caps); + auto basic_info_unsandboxed = + std::make_unique<PrinterBasicInfo>(*basic_info); + unsandboxed_print_backend()->AddValidPrinter( + id, std::move(caps_unsandboxed), std::move(basic_info_unsandboxed)); + } + if (requires_elevated_permissions) { - print_backend()->AddAccessDeniedPrinter(id); + sandboxed_print_backend()->AddAccessDeniedPrinter(id); } else { - print_backend()->AddValidPrinter(id, std::move(caps), - std::move(basic_info)); + sandboxed_print_backend()->AddValidPrinter(id, std::move(caps), + std::move(basic_info)); } } @@ -128,19 +173,60 @@ content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfile> profile_; std::unique_ptr<content::WebContents> initiator_; - scoped_refptr<TestPrintBackend> test_backend_; + scoped_refptr<TestPrintBackend> sandboxed_test_backend_; + scoped_refptr<TestPrintBackend> unsandboxed_test_backend_; std::unique_ptr<LocalPrinterHandlerDefault> local_printer_handler_; // Support for testing via a service instead of with a local task runner. base::test::ScopedFeatureList feature_list_; - mojo::Remote<mojom::PrintBackendService> test_remote_; - std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_; + mojo::Remote<mojom::PrintBackendService> sandboxed_test_remote_; + mojo::Remote<mojom::PrintBackendService> unsandboxed_test_remote_; + std::unique_ptr<PrintBackendServiceTestImpl> sandboxed_print_backend_service_; + std::unique_ptr<PrintBackendServiceTestImpl> + unsandboxed_print_backend_service_; }; -INSTANTIATE_TEST_SUITE_P(All, LocalPrinterHandlerDefaultTest, testing::Bool()); +// Testing class to cover `LocalPrinterHandlerDefault` handling using either a +// local task runner or a service. Makes no attempt to cover fallback when +// using a service, which is handled separately by +// `LocalPrinterHandlerDefaultTestFallback` +class LocalPrinterHandlerDefaultTestProcess + : public LocalPrinterHandlerDefaultTestBase, + public testing::WithParamInterface<bool> { + public: + LocalPrinterHandlerDefaultTestProcess() = default; + LocalPrinterHandlerDefaultTestProcess( + const LocalPrinterHandlerDefaultTestProcess&) = delete; + LocalPrinterHandlerDefaultTestProcess& operator=( + const LocalPrinterHandlerDefaultTestProcess&) = delete; + ~LocalPrinterHandlerDefaultTestProcess() override = default; + + bool UseService() override { return GetParam(); } + bool SupportFallback() override { return false; } +}; + +// Testing class to cover `LocalPrinterHandlerDefault` handling using only a +// service, and to check different behavior for whether fallback is enabled. +class LocalPrinterHandlerDefaultTestFallback + : public LocalPrinterHandlerDefaultTestBase { + public: + LocalPrinterHandlerDefaultTestFallback() = default; + LocalPrinterHandlerDefaultTestFallback( + const LocalPrinterHandlerDefaultTestFallback&) = delete; + LocalPrinterHandlerDefaultTestFallback& operator=( + const LocalPrinterHandlerDefaultTestFallback&) = delete; + ~LocalPrinterHandlerDefaultTestFallback() override = default; + + bool UseService() override { return true; } + bool SupportFallback() override { return true; } +}; + +INSTANTIATE_TEST_SUITE_P(All, + LocalPrinterHandlerDefaultTestProcess, + testing::Bool()); // Tests that getting default printer is successful. -TEST_P(LocalPrinterHandlerDefaultTest, GetDefaultPrinter) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, GetDefaultPrinter) { AddPrinter("printer1", "default1", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/false); AddPrinter("printer2", "non-default2", "description2", /*is_default=*/false, @@ -159,7 +245,7 @@ // Tests that getting default printer gives empty string when no printers are // installed. -TEST_P(LocalPrinterHandlerDefaultTest, GetDefaultPrinterNoneInstalled) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, GetDefaultPrinterNoneInstalled) { std::string default_printer = "dummy"; local_printer_handler()->GetDefaultPrinter( base::BindOnce(&RecordGetDefaultPrinter, std::ref(default_printer))); @@ -169,7 +255,7 @@ EXPECT_TRUE(default_printer.empty()); } -TEST_P(LocalPrinterHandlerDefaultTest, GetPrinters) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, GetPrinters) { AddPrinter("printer1", "default1", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/false); AddPrinter("printer2", "non-default2", "description2", /*is_default=*/false, @@ -221,7 +307,7 @@ EXPECT_EQ(*printers, expected_printers); } -TEST_P(LocalPrinterHandlerDefaultTest, GetPrintersNoneRegistered) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, GetPrintersNoneRegistered) { size_t call_count = 0; std::unique_ptr<base::ListValue> printers; bool is_done = false; @@ -241,24 +327,24 @@ // Tests that fetching capabilities for an existing installed printer is // successful. -TEST_P(LocalPrinterHandlerDefaultTest, StartGetCapabilityValidPrinter) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, StartGetCapabilityValidPrinter) { AddPrinter("printer1", "default1", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/false); - base::Value fetched_caps; + base::Value fetched_caps("dummy"); local_printer_handler()->StartGetCapability( "printer1", base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); RunUntilIdle(); - ASSERT_TRUE(fetched_caps.is_dict()); - EXPECT_TRUE(fetched_caps.FindKey(kSettingCapabilities)); - EXPECT_TRUE(fetched_caps.FindKey(kPrinter)); + EXPECT_TRUE(fetched_caps.FindDictKey(kSettingCapabilities)); + EXPECT_TRUE(fetched_caps.FindDictKey(kPrinter)); } // Tests that fetching capabilities bails early when the provided printer // can't be found. -TEST_P(LocalPrinterHandlerDefaultTest, StartGetCapabilityInvalidPrinter) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, + StartGetCapabilityInvalidPrinter) { base::Value fetched_caps("dummy"); local_printer_handler()->StartGetCapability( /*destination_id=*/"invalid printer", @@ -271,7 +357,7 @@ // Test that installed printers to which the user does not have permission to // access will fail to get any capabilities. -TEST_P(LocalPrinterHandlerDefaultTest, StartGetCapabilityAccessDenied) { +TEST_P(LocalPrinterHandlerDefaultTestProcess, StartGetCapabilityAccessDenied) { AddPrinter("printer1", "default1", "description1", /*is_default=*/true, /*requires_elevated_permissions=*/true); @@ -285,4 +371,30 @@ EXPECT_TRUE(fetched_caps.is_none()); } +// Tests that fetching capabilities can eventually succeed with fallback +// processing when a printer requires elevated permissions. +TEST_F(LocalPrinterHandlerDefaultTestFallback, + StartGetCapabilityElevatedPermissionsSucceeds) { + AddPrinter("printer1", "default1", "description1", /*is_default=*/true, + /*requires_elevated_permissions=*/true); + + // Note that printer does not initially show as requiring elevated privileges. + EXPECT_FALSE(PrintBackendServiceManager::GetInstance() + .PrinterDriverRequiresElevatedPrivilege("printer1")); + + base::Value fetched_caps("dummy"); + local_printer_handler()->StartGetCapability( + /*destination_id=*/"printer1", + base::BindOnce(&RecordGetCapability, std::ref(fetched_caps))); + + RunUntilIdle(); + + EXPECT_TRUE(fetched_caps.FindDictKey(kSettingCapabilities)); + EXPECT_TRUE(fetched_caps.FindDictKey(kPrinter)); + + // Verify that this printer now shows up as requiring elevated privileges. + EXPECT_TRUE(PrintBackendServiceManager::GetInstance() + .PrinterDriverRequiresElevatedPrivilege("printer1")); +} + } // namespace printing
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc index cc9e4ba..962027d8 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc
@@ -36,14 +36,7 @@ } // namespace AccessibilityHandler::AccessibilityHandler(Profile* profile) - : profile_(profile) { - if (::switches::IsExperimentalAccessibilityDictationOfflineEnabled()) { - if (speech::SodaInstaller::GetInstance()->IsSodaInstalled()) - OnSodaInstalled(); - else - speech::SodaInstaller::GetInstance()->AddObserver(this); - } -} + : profile_(profile) {} AccessibilityHandler::~AccessibilityHandler() { if (a11y_nav_buttons_toggle_metrics_reporter_timer_.IsRunning()) @@ -120,6 +113,8 @@ FireWebUIListener( "initial-data-ready", base::Value(AccessibilityManager::Get()->GetStartupSoundEnabled())); + + MaybeAddSodaInstallerObserver(); } void AccessibilityHandler::HandleShowChromeVoxTutorial( @@ -138,6 +133,15 @@ chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); } +void AccessibilityHandler::MaybeAddSodaInstallerObserver() { + if (::switches::IsExperimentalAccessibilityDictationOfflineEnabled()) { + if (speech::SodaInstaller::GetInstance()->IsSodaInstalled()) + OnSodaInstalled(); + else + speech::SodaInstaller::GetInstance()->AddObserver(this); + } +} + // SodaInstaller::Observer: void AccessibilityHandler::OnSodaInstalled() { speech::SodaInstaller::GetInstance()->RemoveObserver(this);
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h index a0bef8eb..f778cfe3 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h
@@ -47,6 +47,8 @@ void OpenExtensionOptionsPage(const char extension_id[]); + void MaybeAddSodaInstallerObserver(); + // SodaInstaller::Observer: void OnSodaInstalled() override; void OnSodaLanguagePackInstalled(
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_browsertest.cc b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_browsertest.cc index 8180941..2b958a3 100644 --- a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_browsertest.cc +++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler_browsertest.cc
@@ -74,6 +74,8 @@ return false; } + void AddSodaInstallerObserver() { handler_->MaybeAddSodaInstallerObserver(); } + void OnSodaInstalled() { handler_->OnSodaInstalled(); } void OnSodaProgress(int progress) { handler_->OnSodaProgress(progress); } @@ -123,6 +125,7 @@ // the correct listener when SODA is installed. IN_PROC_BROWSER_TEST_F(AccessibilityHandlerTest, OnSodaInstalledNotification) { AssertWebUICalls(0); + AddSodaInstallerObserver(); speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); AssertWebUICalls(1); ASSERT_TRUE(WasWebUIListenerCalledWithStringArgument(
diff --git a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc index 0fea9ef1..8df08c03 100644 --- a/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc +++ b/chrome/browser/web_applications/extensions/externally_managed_app_install_task_unittest.cc
@@ -1040,8 +1040,6 @@ const GURL kWebAppUrl("https://foo.example"); ExternalInstallOptions options(kWebAppUrl, DisplayMode::kStandalone, ExternalInstallSource::kSystemInstalled); - options.add_to_desktop = false; - options.add_to_quick_launch_bar = false; options.only_use_app_info_factory = true; options.app_info_factory = base::BindLambdaForTesting([&kWebAppUrl]() { auto info = std::make_unique<WebApplicationInfo>(); @@ -1051,9 +1049,6 @@ return info; }); - os_integration_manager()->SetNextCreateShortcutsResult( - finalizer()->GetAppIdForUrl(options.install_url), true); - ExternallyManagedAppInstallTask task( profile(), /*url_loader=*/nullptr, registrar(), os_integration_manager(), ui_manager(), finalizer(), install_manager(), std::move(options)); @@ -1077,12 +1072,10 @@ EXPECT_EQ(app_id.value(), id.value()); - // Installing with an App Info does call into OS Integration Manager. - absl::optional<InstallOsHooksOptions> os_hooks_options = - os_integration_manager()->get_last_install_options(); - ASSERT_TRUE(os_hooks_options); - EXPECT_FALSE(os_hooks_options->add_to_desktop); - EXPECT_FALSE(os_hooks_options->add_to_quick_launch_bar); + // Installing with an App Info doesn't call into OS Integration Manager. + // This might be an issue for default apps. + EXPECT_FALSE( + os_integration_manager()->get_last_install_options().has_value()); EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls());
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc index 56688267..aa04ee8 100644 --- a/chrome/browser/web_applications/web_app_install_task.cc +++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -239,7 +239,6 @@ install_source_ = install_source; background_installation_ = true; - from_info_ = true; RecordInstallEvent(); @@ -249,22 +248,8 @@ UpdateFinalizerClientData(install_params_, &options); - // If no install params have been set, default to not adding any shortcuts, - // overriding the default used in the install-from-manifest case, which is - // to add shortcuts. - if (!install_params_) { - install_params_ = InstallManager::InstallParams(); - install_params_->add_to_applications_menu = false; - install_params_->add_to_desktop = false; - install_params_->add_to_quick_launch_bar = false; - } - - install_callback_ = std::move(callback); - WebApplicationInfo web_application_info_copy = *web_application_info; - install_finalizer_->FinalizeInstall( - web_application_info_copy, options, - base::BindOnce(&WebAppInstallTask::OnInstallFinalizedCreateOsHooks, - GetWeakPtr(), std::move(web_application_info))); + install_finalizer_->FinalizeInstall(*web_application_info, options, + std::move(callback)); } void WebAppInstallTask::InstallWebAppWithParams( @@ -398,9 +383,8 @@ bool WebAppInstallTask::ShouldStopInstall() const { // Install should stop early if WebContents is being destroyed. // WebAppInstallTask::WebContentsDestroyed will get called eventually and - // the callback will be invoked at that point. Installs from info don't have a - // web contents, so this should always return false in that case. - return !from_info_ && (!web_contents() || web_contents()->IsBeingDestroyed()); + // the callback will be invoked at that point. + return !web_contents() || web_contents()->IsBeingDestroyed(); } void WebAppInstallTask::OnWebAppUrlLoadedGetWebApplicationInfo( @@ -820,10 +804,10 @@ install_finalizer_->FinalizeInstall( web_app_info_copy, finalize_options, - base::BindOnce(&WebAppInstallTask::OnInstallFinalizedCreateOsHooks, + base::BindOnce(&WebAppInstallTask::OnInstallFinalizedCreateShortcuts, GetWeakPtr(), std::move(web_app_info))); - // Check that the finalizer hasn't called OnInstallFinalizedCreateOsHooks + // Check that the finalizer hasn't called OnInstallFinalizedCreateShortcuts // synchronously: DCHECK(install_callback_); } @@ -836,7 +820,7 @@ CallInstallCallback(app_id, code); } -void WebAppInstallTask::OnInstallFinalizedCreateOsHooks( +void WebAppInstallTask::OnInstallFinalizedCreateShortcuts( std::unique_ptr<WebApplicationInfo> web_app_info, const AppId& app_id, InstallResultCode code) { @@ -863,8 +847,7 @@ } // Only record the AppBanner stats for locally installed apps. - if (web_contents()) - RecordAppBanner(web_contents(), web_app_info->start_url); + RecordAppBanner(web_contents(), web_app_info->start_url); InstallOsHooksOptions options;
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h index ba5ba8c..fdd1b3c 100644 --- a/chrome/browser/web_applications/web_app_install_task.h +++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -242,7 +242,7 @@ bool user_accepted, std::unique_ptr<WebApplicationInfo> web_app_info); void OnInstallFinalized(const AppId& app_id, InstallResultCode code); - void OnInstallFinalizedCreateOsHooks( + void OnInstallFinalizedCreateShortcuts( std::unique_ptr<WebApplicationInfo> web_app_info, const AppId& app_id, InstallResultCode code); @@ -265,10 +265,6 @@ absl::optional<AppId> expected_app_id_; bool background_installation_ = false; - // True when the install is initiated from InstallWebAppFromInfo. In this - // case, there will be no WebContents. - bool from_info_ = false; - // The mechanism via which the app creation was triggered, will stay as // kNoInstallSource for updates. static constexpr webapps::WebappInstallSource kNoInstallSource = @@ -285,6 +281,7 @@ AppRegistrar* registrar_; base::WeakPtrFactory<WebAppInstallTask> weak_ptr_factory_{this}; + }; } // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc index ca7ec06..12b4bc6 100644 --- a/chrome/browser/web_applications/web_app_install_task_unittest.cc +++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -837,6 +837,32 @@ test_os_integration_manager().num_add_app_to_quick_launch_bar_calls()); } +TEST_F(WebAppInstallTaskTest, InstallWebAppFromManifest_Success) { + const GURL url = GURL("https://example.com/path"); + const AppId app_id = GenerateAppIdFromURL(url); + + auto manifest = std::make_unique<blink::Manifest>(); + manifest->start_url = url; + manifest->short_name = u"Server Name"; + + data_retriever_->SetManifest(std::move(manifest), /*is_installable=*/true); + + base::RunLoop run_loop; + + install_task_->InstallWebAppFromManifest( + web_contents(), /*bypass_service_worker_check=*/false, + webapps::WebappInstallSource::MENU_BROWSER_TAB, + base::BindOnce(test::TestAcceptDialogCallback), + base::BindLambdaForTesting( + [&](const AppId& installed_app_id, InstallResultCode code) { + EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code); + EXPECT_EQ(app_id, installed_app_id); + run_loop.Quit(); + })); + + run_loop.Run(); +} + TEST_F(WebAppInstallTaskTest, InstallWebAppFromInfo_Success) { SetInstallFinalizerForTesting(); @@ -866,48 +892,6 @@ })); run_loop.Run(); - - // With no install params set, OS hooks are run but no shortcuts are created. - EXPECT_EQ(0u, test_os_integration_manager().num_create_shortcuts_calls()); - EXPECT_EQ(1u, test_os_integration_manager().num_create_file_handlers_calls()); -} - -TEST_F(WebAppInstallTaskTest, InstallWebAppFromInfo_WithInstallParams) { - SetInstallFinalizerForTesting(); - - const GURL url = GURL("https://example.com/path"); - const AppId app_id = GenerateAppIdFromURL(url); - - auto web_app_info = std::make_unique<WebApplicationInfo>(); - web_app_info->start_url = url; - web_app_info->open_as_window = true; - web_app_info->title = u"App Name"; - - // Set install params that add shortcuts. - install_task_->SetInstallParams(InstallManager::InstallParams()); - - base::RunLoop run_loop; - - install_task_->InstallWebAppFromInfo( - std::move(web_app_info), ForInstallableSite::kYes, - webapps::WebappInstallSource::MENU_BROWSER_TAB, - base::BindLambdaForTesting( - [&](const AppId& installed_app_id, InstallResultCode code) { - EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code); - EXPECT_EQ(app_id, installed_app_id); - - std::unique_ptr<WebApplicationInfo> final_web_app_info = - test_install_finalizer().web_app_info(); - EXPECT_TRUE(final_web_app_info->open_as_window); - - run_loop.Quit(); - })); - - run_loop.Run(); - - // OS hooks are run and shortcuts are created. - EXPECT_EQ(1u, test_os_integration_manager().num_create_shortcuts_calls()); - EXPECT_EQ(1u, test_os_integration_manager().num_create_file_handlers_calls()); } TEST_F(WebAppInstallTaskTest, InstallWebAppFromInfo_GenerateIcons) {
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc index 40360f5..9c7d24b1 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/ui/webauthn/authenticator_request_dialog.h" #include "chrome/browser/webauthn/authenticator_request_dialog_model.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/device_event_log/device_event_log.h" @@ -234,20 +235,22 @@ ChromeWebAuthenticationDelegate::TouchIdAuthenticatorConfig ChromeWebAuthenticationDelegate::TouchIdAuthenticatorConfigForProfile( Profile* profile) { - constexpr char kTouchIdKeychainAccessGroup[] = - "EQHXZ8M8AV.com.google.Chrome.webauthn"; - PrefService* prefs = profile->GetPrefs(); + constexpr char kKeychainAccessGroup[] = + MAC_TEAM_IDENTIFIER_STRING "." MAC_BUNDLE_IDENTIFIER_STRING ".webauthn"; + std::string metadata_secret = - prefs->GetString(kWebAuthnTouchIdMetadataSecretPrefName); + profile->GetPrefs()->GetString(kWebAuthnTouchIdMetadataSecretPrefName); if (metadata_secret.empty() || !base::Base64Decode(metadata_secret, &metadata_secret)) { metadata_secret = device::fido::mac::GenerateCredentialMetadataSecret(); - prefs->SetString( + profile->GetPrefs()->SetString( kWebAuthnTouchIdMetadataSecretPrefName, base::Base64Encode(base::as_bytes(base::make_span(metadata_secret)))); } - return TouchIdAuthenticatorConfig{kTouchIdKeychainAccessGroup, - std::move(metadata_secret)}; + + return TouchIdAuthenticatorConfig{ + .keychain_access_group = kKeychainAccessGroup, + .metadata_secret = std::move(metadata_secret)}; } absl::optional<ChromeWebAuthenticationDelegate::TouchIdAuthenticatorConfig>
diff --git a/chrome/browser/window_placement/window_placement_permission_context.cc b/chrome/browser/window_placement/window_placement_permission_context.cc index faf480e..f0623ec5b 100644 --- a/chrome/browser/window_placement/window_placement_permission_context.cc +++ b/chrome/browser/window_placement/window_placement_permission_context.cc
@@ -15,7 +15,7 @@ : permissions::PermissionContextBase( browser_context, ContentSettingsType::WINDOW_PLACEMENT, - blink::mojom::PermissionsPolicyFeature::kNotFound) {} + blink::mojom::PermissionsPolicyFeature::kWindowPlacement) {} WindowPlacementPermissionContext::~WindowPlacementPermissionContext() = default;
diff --git a/chrome/browser/window_placement/window_placement_permission_context_browsertest.cc b/chrome/browser/window_placement/window_placement_permission_context_browsertest.cc index 9faa15ff..c119c1be 100644 --- a/chrome/browser/window_placement/window_placement_permission_context_browsertest.cc +++ b/chrome/browser/window_placement/window_placement_permission_context_browsertest.cc
@@ -12,6 +12,8 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" namespace { @@ -31,12 +33,35 @@ switches::kEnableBlinkFeatures, "WindowPlacement"); InProcessBrowserTest::SetUpCommandLine(command_line); } + + void SetUpOnMainThread() override { + // Support multiple sites on the test server. + host_resolver()->AddRule("*", "127.0.0.1"); + + // Window placement features are only available on secure contexts, and so + // we need to create an HTTPS test server here to serve those pages rather + // than using the default embedded_test_server(). + https_test_server_ = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + // Support sites like a.test, b.test, c.test etc + https_test_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); + https_test_server_->ServeFilesFromSourceDirectory("chrome/test/data"); + net::test_server::RegisterDefaultHandlers(https_test_server_.get()); + content::SetupCrossSiteRedirector(https_test_server_.get()); + ASSERT_TRUE(https_test_server_->Start()); + } + + net::EmbeddedTestServer* https_test_server() { + return https_test_server_.get(); + } + + protected: + std::unique_ptr<net::EmbeddedTestServer> https_test_server_; }; // Tests user activation after dimissing and denying the permission request. IN_PROC_BROWSER_TEST_F(WindowPlacementPermissionContextTest, DismissAndDeny) { - ASSERT_TRUE(embedded_test_server()->Start()); - const GURL url(embedded_test_server()->GetURL("/empty.html")); + const GURL url(https_test_server()->GetURL("a.test", "/empty.html")); EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_FALSE(tab->GetMainFrame()->HasTransientUserActivation()); @@ -61,8 +86,7 @@ // Tests user activation after accepting the permission request. IN_PROC_BROWSER_TEST_F(WindowPlacementPermissionContextTest, Accept) { - ASSERT_TRUE(embedded_test_server()->Start()); - const GURL url(embedded_test_server()->GetURL("/empty.html")); + const GURL url(https_test_server()->GetURL("a.test", "/empty.html")); EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_FALSE(tab->GetMainFrame()->HasTransientUserActivation()); @@ -78,4 +102,85 @@ EXPECT_TRUE(tab->GetMainFrame()->HasTransientUserActivation()); } +IN_PROC_BROWSER_TEST_F(WindowPlacementPermissionContextTest, + IFrameSameOriginAllow) { + const GURL url(https_test_server()->GetURL("a.test", "/iframe.html")); + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); + + content::RenderFrameHost* child = ChildFrameAt(tab->GetMainFrame(), 0); + ASSERT_TRUE(child); + EXPECT_FALSE(tab->GetMainFrame()->HasTransientUserActivation()); + EXPECT_FALSE(child->GetMainFrame()->HasTransientUserActivation()); + + permissions::PermissionRequestManager* permission_request_manager = + permissions::PermissionRequestManager::FromWebContents(tab); + + permission_request_manager->set_auto_response_for_test( + permissions::PermissionRequestManager::ACCEPT_ALL); + EXPECT_EQ("granted", EvalJs(child, kGetScreens, + content::EXECUTE_SCRIPT_NO_USER_GESTURE)); + EXPECT_TRUE(tab->GetMainFrame()->HasTransientUserActivation()); + EXPECT_TRUE(child->GetMainFrame()->HasTransientUserActivation()); +} + +IN_PROC_BROWSER_TEST_F(WindowPlacementPermissionContextTest, + IFrameCrossOriginDeny) { + const GURL url(https_test_server()->GetURL("a.test", "/iframe.html")); + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); + + GURL subframe_url(https_test_server()->GetURL("b.test", "/title1.html")); + content::NavigateIframeToURL(tab, /*iframe_id=*/"test", subframe_url); + + content::RenderFrameHost* child = ChildFrameAt(tab->GetMainFrame(), 0); + ASSERT_TRUE(child); + EXPECT_FALSE(tab->GetMainFrame()->HasTransientUserActivation()); + EXPECT_FALSE(child->GetMainFrame()->HasTransientUserActivation()); + + permissions::PermissionRequestManager* permission_request_manager = + permissions::PermissionRequestManager::FromWebContents(tab); + + // PermissionRequestManager will accept any window placement permission + // dialogs that appear. However, the window-placement permission is not + // explicitly allowed on the iframe, so requests made by the child frame will + // be automatically denied before a prompt might be issued + permission_request_manager->set_auto_response_for_test( + permissions::PermissionRequestManager::ACCEPT_ALL); + EXPECT_EQ("denied", EvalJs(child, kGetScreens, + content::EXECUTE_SCRIPT_NO_USER_GESTURE)); + EXPECT_FALSE(tab->GetMainFrame()->HasTransientUserActivation()); + EXPECT_FALSE(child->GetMainFrame()->HasTransientUserActivation()); +} + +IN_PROC_BROWSER_TEST_F(WindowPlacementPermissionContextTest, + IFrameCrossOriginExplicitAllow) { + const GURL url(https_test_server()->GetURL("a.test", "/iframe.html")); + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + auto* tab = browser()->tab_strip_model()->GetActiveWebContents(); + + // See https://w3c.github.io/webappsec-permissions-policy/ for more + // information on permissions policies and allowing cross-origin iframes + // to have particular permissions. + // + // TODO(enne): This code causes a user activation, so can't check that below + // like other tests. Figure out why this is and try to clear it / address it. + EXPECT_TRUE(ExecJs(tab, R"(const frame = document.getElementById('test'); + frame.setAttribute('allow', 'window-placement');)")); + + GURL subframe_url(https_test_server()->GetURL("b.test", "/title1.html")); + content::NavigateIframeToURL(tab, /*iframe_id=*/"test", subframe_url); + + content::RenderFrameHost* child = ChildFrameAt(tab->GetMainFrame(), 0); + ASSERT_TRUE(child); + + permissions::PermissionRequestManager* permission_request_manager = + permissions::PermissionRequestManager::FromWebContents(tab); + + permission_request_manager->set_auto_response_for_test( + permissions::PermissionRequestManager::ACCEPT_ALL); + EXPECT_EQ("granted", EvalJs(child, kGetScreens, + content::EXECUTE_SCRIPT_NO_USER_GESTURE)); +} + } // namespace
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 82ba0b0f..b80b30b6 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1621349817-1d50b69a5e4482ba6511550a3d6135cafd061111.profdata +chrome-win32-master-1621382314-880123e5c4c4f5ae58f6b0ec6d73e103020a9443.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 986af74..ea18550 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1621349817-519d8eae9c154f5a52e78d5c4f4b361cf53da7a0.profdata +chrome-win64-master-1621382314-37d89922e41e14aa748bc033bf556a6b727eb5d1.profdata
diff --git a/chrome/chrome_cleaner/test/cleaner_test.cc b/chrome/chrome_cleaner/test/cleaner_test.cc index 0b02d8f..8d0121c 100644 --- a/chrome/chrome_cleaner/test/cleaner_test.cc +++ b/chrome/chrome_cleaner/test/cleaner_test.cc
@@ -603,6 +603,12 @@ void SetUp() override { CleanerTestBase::SetUp(); + // TODO(crbug.com/1210601): All uses of MockChromePromptResponder are + // failing on Windows 7. Disable this test suite until the problem can be + // investigated. + if (base::win::GetVersion() < base::win::Version::WIN8) + GTEST_SKIP() << "Skipping on Win7: crbug.com/1210601"; + command_line_ = BuildCommandLine(kCleanerExecutable, ExecutionMode::kScanning); chrome_cleaner::ChromePromptPipeHandles pipe_handles =
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 1acffc9..941ee46 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -7,6 +7,7 @@ import("//chrome/browser/buildflags.gni") import("//chrome/common/features.gni") import("//extensions/buildflags/buildflags.gni") +import("//pdf/features.gni") import("//ui/base/ui_features.gni") import("chrome_repack_locales.gni") @@ -296,7 +297,7 @@ "//extensions:extensions_resources", ] } - if (enable_plugins) { + if (enable_pdf) { sources += [ "$root_gen_dir/chrome/pdf_resources.pak" ] deps += [ "//chrome/browser/resources/pdf:resources" ] }
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 9738c237..195f082 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -246,6 +246,7 @@ "//build:chromeos_buildflags", "//components/crash/core/app", "//components/google/core/common", + "//components/live_caption:constants", "//components/metrics:call_stack_profile_builder", "//components/no_state_prefetch/common", "//components/no_state_prefetch/common:mojo_bindings",
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index 699d95885..897ccf7 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS
@@ -22,6 +22,7 @@ "+components/flags_ui/flags_ui_switches.h", "+components/gcm_driver", "+components/google/core/common", + "+components/live_caption/pref_names.h", "+components/metrics/client_info.h", "+components/metrics/metadata_recorder.h", "+components/metrics/metrics_pref_names.h",
diff --git a/chrome/common/chrome_version.h.in b/chrome/common/chrome_version.h.in index f4d88ff..0b2944f 100644 --- a/chrome/common/chrome_version.h.in +++ b/chrome/common/chrome_version.h.in
@@ -22,3 +22,8 @@ #define PRODUCT_SHORTNAME_STRING "@PRODUCT_SHORTNAME@" #define COPYRIGHT_STRING "@COPYRIGHT@" #define OFFICIAL_BUILD_STRING "@OFFICIAL_BUILD@" + +// Distribution Information + +#define MAC_BUNDLE_IDENTIFIER_STRING "@MAC_BUNDLE_ID@" +#define MAC_TEAM_IDENTIFIER_STRING "@MAC_TEAM_ID@"
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json index 28ce8df7..7f80235 100644 --- a/chrome/common/extensions/api/accessibility_private.json +++ b/chrome/common/extensions/api/accessibility_private.json
@@ -80,7 +80,7 @@ "id": "SwitchAccessMenuAction", "type": "string", "enum": [ "copy", "cut", "decrement", "dictation", "endTextSelection", "increment", "itemScan", "jumpToBeginningOfText", "jumpToEndOfText", "keyboard", "leftClick", "moveBackwardOneCharOfText", "moveBackwardOneWordOfText", "moveCursor", "moveDownOneLineOfText", "moveForwardOneCharOfText", "moveForwardOneWordOfText", "moveUpOneLineOfText", "paste", "pointScan", "rightClick", "scrollDown", "scrollLeft", "scrollRight", "scrollUp", "select", "settings", "startTextSelection" ], - "description": "Available actions to be shown in the Switch Access menu. Must be kept in sync with the strings in ash/system/accessibility/switch_access_menu_view.cc" + "description": "Available actions to be shown in the Switch Access menu. Must be kept in sync with the strings in ash/system/accessibility/switch_access/switch_access_menu_view.cc" }, { "id": "SyntheticKeyboardEventType",
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl index 9c74214..05dd159 100644 --- a/chrome/common/extensions/api/autotest_private.idl +++ b/chrome/common/extensions/api/autotest_private.idl
@@ -1036,8 +1036,8 @@ // Create mouse events to move a mouse cursor to the location. This can // cause a dragging if a button is pressed. It starts from the last mouse - // location. It does not support the move or drag across display boundaries. - // |location|: the target location (in display's coordinate). + // location. + // |location|: the target location (in screen coordinate). // |duration_in_ms|: the duration (in milliseconds) for the mouse movement. // The mouse will move linearly. 0 means moving immediately. // |callback|: called after the mouse move finishes.
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 438a68e31..c1b22016 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1185,34 +1185,6 @@ const char kDefaultBrowserSettingEnabled[] = "browser.default_browser_setting_enabled"; -// String indicating the size of the captions text as a percentage. -const char kAccessibilityCaptionsTextSize[] = - "accessibility.captions.text_size"; - -// String indicating the font of the captions text. -const char kAccessibilityCaptionsTextFont[] = - "accessibility.captions.text_font"; - -// Comma-separated string indicating the RGB values of the captions text color. -const char kAccessibilityCaptionsTextColor[] = - "accessibility.captions.text_color"; - -// Integer indicating the opacity of the captions text from 0 - 100. -const char kAccessibilityCaptionsTextOpacity[] = - "accessibility.captions.text_opacity"; - -// Comma-separated string indicating the RGB values of the background color. -const char kAccessibilityCaptionsBackgroundColor[] = - "accessibility.captions.background_color"; - -// CSS string indicating the shadow of the captions text. -const char kAccessibilityCaptionsTextShadow[] = - "accessibility.captions.text_shadow"; - -// Integer indicating the opacity of the captions text background from 0 - 100. -const char kAccessibilityCaptionsBackgroundOpacity[] = - "accessibility.captions.background_opacity"; - // Boolean that indicates whether chrome://accessibility should show the // internal accessibility tree. const char kShowInternalAccessibilityTree[] = @@ -3221,6 +3193,8 @@ // Boolean pref indicating whether user has enabled rule-based discount in cart // module. const char kCartDiscountEnabled[] = "cart_discount_enabled"; +// Map pref recording the discounts used by users. +const char kCartUsedDiscounts[] = "cart_used_discounts"; #endif #if defined(OS_ANDROID)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index d314fc4d..11a1620 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -186,13 +186,6 @@ #if !BUILDFLAG(IS_CHROMEOS_ASH) extern const char kAccessibilityFocusHighlightEnabled[]; #endif -extern const char kAccessibilityCaptionsTextSize[]; -extern const char kAccessibilityCaptionsTextFont[]; -extern const char kAccessibilityCaptionsTextColor[]; -extern const char kAccessibilityCaptionsTextOpacity[]; -extern const char kAccessibilityCaptionsBackgroundColor[]; -extern const char kAccessibilityCaptionsTextShadow[]; -extern const char kAccessibilityCaptionsBackgroundOpacity[]; #if !defined(OS_ANDROID) extern const char kLiveCaptionEnabled[]; extern const char kLiveCaptionLanguageCode[]; @@ -1134,6 +1127,7 @@ extern const char kCartModuleWelcomeSurfaceShownTimes[]; extern const char kCartDiscountAcknowledged[]; extern const char kCartDiscountEnabled[]; +extern const char kCartUsedDiscounts[]; #endif #if defined(OS_ANDROID)
diff --git a/chrome/common/pref_names_util.cc b/chrome/common/pref_names_util.cc index 98d62b0..9dbb829 100644 --- a/chrome/common/pref_names_util.cc +++ b/chrome/common/pref_names_util.cc
@@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "chrome/common/pref_names.h" +#include "components/live_caption/pref_names.h" #include "components/prefs/pref_service.h" #include "ui/native_theme/native_theme.h"
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index 46f8728..93e8eba 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -284,7 +284,8 @@ const char kChromeUIPasswordChangeUrl[] = "chrome://password-change"; const char kChromeUIPrintManagementUrl[] = "chrome://print-management"; const char kChromeUIPowerHost[] = "power"; -const char kChromeUIProjectorHost[] = "projector"; +const char kChromeUIProjectorSelfieCamHost[] = "projector-selfie-cam"; +const char kChromeUIProjectorSelfieCamURL[] = "chrome://projector-selfie-cam/"; const char kChromeUIScanningAppURL[] = "chrome://scanning"; const char kChromeUIScreenlockIconHost[] = "screenlock-icon"; const char kChromeUIScreenlockIconURL[] = "chrome://screenlock-icon/";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index cbe9b3e..e2ef915 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -273,7 +273,8 @@ extern const char kChromeUIPasswordChangeUrl[]; extern const char kChromeUIPrintManagementUrl[]; extern const char kChromeUIPowerHost[]; -extern const char kChromeUIProjectorHost[]; +extern const char kChromeUIProjectorSelfieCamHost[]; +extern const char kChromeUIProjectorSelfieCamURL[]; extern const char kChromeUIScanningAppURL[]; extern const char kChromeUIScreenlockIconHost[]; extern const char kChromeUIScreenlockIconURL[];
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index 70c976d2..4dca660 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -11,6 +11,7 @@ import("//components/spellcheck/spellcheck_build_features.gni") import("//extensions/buildflags/buildflags.gni") import("//media/media_options.gni") +import("//pdf/features.gni") import("//ppapi/buildflags/buildflags.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -258,7 +259,6 @@ "plugins/chrome_plugin_placeholder.h", ] deps += [ - "//components/pdf/renderer", "//components/strings", "//media:media_buildflags", "//ppapi/host", @@ -272,6 +272,10 @@ } } + if (enable_pdf) { + deps += [ "//components/pdf/renderer" ] + } + if (is_chromeos_ash) { deps += [ "//ash/constants" ] }
diff --git a/chrome/renderer/cart/DEPS b/chrome/renderer/cart/DEPS index f2952a21..5a4b108 100644 --- a/chrome/renderer/cart/DEPS +++ b/chrome/renderer/cart/DEPS
@@ -3,6 +3,7 @@ "+chrome/browser/signin", "+chrome/browser", "+components/signin/public/identity_manager", + "+components/prefs", ] specific_include_rules = {
diff --git a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc index bfe85a0..25c1b68 100644 --- a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc +++ b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc
@@ -12,9 +12,11 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/chrome_test_utils.h" #include "components/network_session_configurator/common/network_switches.h" #include "components/optimization_guide/core/optimization_guide_features.h" +#include "components/prefs/pref_service.h" #include "components/search/ntp_features.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_utils.h" @@ -529,7 +531,9 @@ void SetUpInProcessBrowserTestFixture() override { scoped_feature_list_.InitWithFeaturesAndParameters( {{ntp_features::kNtpChromeCartModule, - {{"partner-merchant-pattern", "(guitarcenter.com)"}, + {{ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam, + "true"}, + {"partner-merchant-pattern", "(guitarcenter.com)"}, {"product-skip-pattern", "(^|\\W)(?i)(skipped)(\\W|$)"}}}}, {optimization_guide::features::kOptimizationHints}); } @@ -589,4 +593,20 @@ WaitForProductCount(expected_carts); } +IN_PROC_BROWSER_TEST_F(CommerceHintProductInfoTest, + RBDPartnerCartURLNotOverwrite) { + Profile* profile = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()); + profile->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true); + EXPECT_TRUE(service_->IsCartDiscountEnabled()); + + NavigateToURL("https://www.guitarcenter.com/"); + SendXHR("/add-to-cart", "product: 123"); + + WaitForCartCount(kExpectedExampleFallbackCart); + NavigateToURL("https://www.guitarcenter.com/cart.html"); + + WaitForCartCount(kExpectedExampleFallbackCart); +} + } // namespace
diff --git a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc index 7820a55..60cfd89 100644 --- a/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc +++ b/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc
@@ -10,6 +10,7 @@ #include "chrome/renderer/pepper/pepper_uma_host.h" #include "components/pdf/renderer/pepper_pdf_host.h" #include "content/public/renderer/renderer_ppapi_host.h" +#include "pdf/buildflags.h" #include "ppapi/host/ppapi_host.h" #include "ppapi/host/resource_host.h" #include "ppapi/proxy/ppapi_message_utils.h" @@ -67,6 +68,7 @@ } } +#if BUILDFLAG(ENABLE_PDF) if (host_->GetPpapiHost()->permissions().HasPermission( ppapi::PERMISSION_PDF)) { switch (message.type()) { @@ -75,6 +77,7 @@ } } } +#endif // Permissions for the following interfaces will be checked at the // time of the corresponding instance's method calls. Currently these
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 0a39e03..5bb2775 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1084,9 +1084,9 @@ "../browser/accessibility/accessibility_labels_service_browsertest.cc", "../browser/accessibility/browser_accessibility_state_browsertest.cc", "../browser/accessibility/caption_controller_browsertest.cc", - "../browser/accessibility/caption_host_impl_browsertest.cc", "../browser/accessibility/image_annotation_browsertest.cc", "../browser/accessibility/interstitial_accessibility_browsertest.cc", + "../browser/accessibility/live_caption_speech_recognition_host_browsertest.cc", "../browser/apps/guest_view/app_view_browsertest.cc", "../browser/apps/guest_view/web_view_browsertest.cc", "../browser/apps/platform_apps/app_browsertest.cc", @@ -3003,6 +3003,7 @@ "../browser/ui/ash/keyboard/keyboard_end_to_end_browsertest.cc", "../browser/ui/ash/multi_user/test_multi_user_window_manager.cc", "../browser/ui/ash/multi_user/test_multi_user_window_manager.h", + "../browser/ui/ash/projector/projector_client_impl_browsertest.cc", "../browser/ui/ash/recording_service_browsertest.cc", "../browser/ui/ash/screen_orientation_delegate_chromeos_browsertest.cc", "../browser/ui/ash/sharesheet/sharesheet_bubble_view_browsertest.cc",
diff --git a/chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.js b/chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.js index 082f6e5..3267de0 100644 --- a/chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_toolbar_focus_tests.js
@@ -5,7 +5,7 @@ /** @fileoverview Suite of tests for cr-toolbar. */ // clang-format off -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js'; // clang-format on
diff --git a/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js b/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js index f8f0d686..b51f7ac98 100644 --- a/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. // clang-format off -import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; +import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -20,7 +20,7 @@ /** @param {string} term */ function simulateSearch(term) { - field.$$('#searchInput').value = term; + field.shadowRoot.querySelector('#searchInput').value = term; field.onSearchTermInput(); field.onSearchTermSearch(); } @@ -59,10 +59,11 @@ assertFalse(field.showingSearch); field.click(); assertTrue(field.showingSearch); - const searchInput = /** @type {!HTMLElement} */ (field.$$('#searchInput')); + const searchInput = /** @type {!HTMLElement} */ ( + field.shadowRoot.querySelector('#searchInput')); assertEquals(searchInput, field.root.activeElement); - field.$$('#searchInput').blur(); + field.shadowRoot.querySelector('#searchInput').blur(); assertFalse(field.showingSearch); field.click(); @@ -79,12 +80,14 @@ flush(); assertTrue(field.hasSearchText); - const clearSearch = field.$$('#clearSearch'); + const clearSearch = field.shadowRoot.querySelector('#clearSearch'); clearSearch.focus(); clearSearch.click(); assertTrue(field.showingSearch); assertEquals('', field.getValue()); - assertEquals(field.$$('#searchInput'), field.root.activeElement); + assertEquals( + field.shadowRoot.querySelector('#searchInput'), + field.root.activeElement); assertFalse(field.hasSearchText); assertFalse(field.spinnerActive); }); @@ -95,7 +98,7 @@ flush(); assertEquals('query1', field.getValue()); - field.$$('#clearSearch').click(); + field.shadowRoot.querySelector('#clearSearch').click(); assertTrue(field.showingSearch); assertEquals('', field.getValue()); @@ -193,7 +196,7 @@ test('blur does not close field when a search is active', function() { field.click(); simulateSearch('test'); - field.$$('#searchInput').blur(); + field.shadowRoot.querySelector('#searchInput').blur(); assertTrue(field.showingSearch); }); @@ -207,13 +210,13 @@ assertTrue(field.hasSearchText); flush(); - const clearSearch = field.$$('#clearSearch'); + const clearSearch = field.shadowRoot.querySelector('#clearSearch'); assertFalse(clearSearch.hidden); assertTrue(field.showingSearch); }); test('closes when value is cleared while unfocused', function() { - field.$$('#searchInput').focus(); + field.shadowRoot.querySelector('#searchInput').focus(); simulateSearch('test'); flush(); @@ -224,7 +227,7 @@ // Does close the field if it is blurred before being cleared. simulateSearch('test'); - field.$$('#searchInput').blur(); + field.shadowRoot.querySelector('#searchInput').blur(); field.setValue(''); assertFalse(field.showingSearch); });
diff --git a/chrome/test/data/webui/downloads/toolbar_tests.js b/chrome/test/data/webui/downloads/toolbar_tests.js index b2ff8ab..f4caa70d 100644 --- a/chrome/test/data/webui/downloads/toolbar_tests.js +++ b/chrome/test/data/webui/downloads/toolbar_tests.js
@@ -38,13 +38,15 @@ }); test('search starts spinner', function() { - toolbar.$.toolbar.fire('search-changed', 'a'); + toolbar.$.toolbar.dispatchEvent(new CustomEvent( + 'search-changed', {composed: true, bubbles: true, detail: 'a'})); assertTrue(toolbar.spinnerActive); // Pretend the manager got results and set this to false. toolbar.spinnerActive = false; - toolbar.$.toolbar.fire('search-changed', 'a '); // Same term plus a space. + toolbar.$.toolbar.dispatchEvent(new CustomEvent( + 'search-changed', {composed: true, bubbles: true, detail: 'a '})); assertFalse(toolbar.spinnerActive); });
diff --git a/chrome/test/data/webui/extensions/manager_test.js b/chrome/test/data/webui/extensions/manager_test.js index 17955e3..cf8ac98 100644 --- a/chrome/test/data/webui/extensions/manager_test.js +++ b/chrome/test/data/webui/extensions/manager_test.js
@@ -82,7 +82,10 @@ }); test(assert(extension_manager_tests.TestNames.ChangePages), function() { - manager.$$('extensions-toolbar').$$('cr-toolbar').$$('#menuButton').click(); + manager.$$('extensions-toolbar') + .$$('cr-toolbar') + .shadowRoot.querySelector('#menuButton') + .click(); flush(); // We start on the item list.
diff --git a/chrome/test/data/webui/history/history_drawer_test.js b/chrome/test/data/webui/history/history_drawer_test.js index cd659d0b9..e8e0bbfb 100644 --- a/chrome/test/data/webui/history/history_drawer_test.js +++ b/chrome/test/data/webui/history/history_drawer_test.js
@@ -33,7 +33,9 @@ // opened. assertFalse(!!drawerSideBar); - const menuButton = app.$.toolbar.$['main-toolbar'].$$('#menuButton'); + const menuButton = + app.$.toolbar.$['main-toolbar'].shadowRoot.querySelector( + '#menuButton'); assertTrue(!!menuButton); menuButton.click();
diff --git a/chrome/test/data/webui/history/history_toolbar_test.js b/chrome/test/data/webui/history/history_toolbar_test.js index 41a1ac2..b0b9776e7 100644 --- a/chrome/test/data/webui/history/history_toolbar_test.js +++ b/chrome/test/data/webui/history/history_toolbar_test.js
@@ -65,7 +65,8 @@ testService.setQueryResult( {info: createHistoryInfo('Test'), value: TEST_HISTORY_RESULTS}); toolbar.shadowRoot.querySelector('cr-toolbar') - .fire('search-changed', 'Test'); + .dispatchEvent(new CustomEvent( + 'search-changed', {bubbles: true, composed: true, detail: 'Test'})); return testService.whenCalled('queryHistory').then(query => { assertEquals('Test', query); }); @@ -79,7 +80,9 @@ value: TEST_HISTORY_RESULTS, }); toolbar.shadowRoot.querySelector('cr-toolbar') - .fire('search-changed', 'Test2'); + .dispatchEvent(new CustomEvent( + 'search-changed', + {bubbles: true, composed: true, detail: 'Test2'})); return testService.whenCalled('queryHistory') .then(flushTasks) .then(() => {
diff --git a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js index 90bf8d27..b9adc52 100644 --- a/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js +++ b/chrome/test/data/webui/settings/chromeos/cellular_networks_list_test.js
@@ -427,13 +427,16 @@ inhibitReason: mojom.InhibitReason.kNotInhibited }; addESimSlot(); - + cellularNetworkList.canShowSpinner = true; await flushAsync(); const inhibitedSubtext = cellularNetworkList.$$('#inhibitedSubtext'); - const inhibitedSpinner = cellularNetworkList.$$('#inhibitedSpinner'); + const getInhibitedSpinner = () => { + return cellularNetworkList.$$('#inhibitedSpinner'); + }; assertTrue(inhibitedSubtext.hidden); - assertFalse(inhibitedSpinner.active); + assertTrue(!!getInhibitedSpinner()); + assertFalse(getInhibitedSpinner().active); cellularNetworkList.cellularDeviceState = { type: mojom.NetworkType.kCellular, @@ -443,6 +446,11 @@ addESimSlot(); await flushAsync(); assertFalse(inhibitedSubtext.hidden); - assertTrue(inhibitedSpinner.active); + assertTrue(getInhibitedSpinner().active); + + // Do not show inihibited spinner if cellular setup dialog is open. + cellularNetworkList.canShowSpinner = false; + await flushAsync(); + assertFalse(!!getInhibitedSpinner()); }); });
diff --git a/chrome/test/data/webui/settings/settings_ui_tests.js b/chrome/test/data/webui/settings/settings_ui_tests.js index 5469a55..bec8908 100644 --- a/chrome/test/data/webui/settings/settings_ui_tests.js +++ b/chrome/test/data/webui/settings/settings_ui_tests.js
@@ -4,7 +4,7 @@ // clang-format off import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {CrSettingsPrefs, Router, routes} from 'chrome://settings/settings.js'; +import {CrSettingsPrefs, CrToolbarElement, CrToolbarSearchFieldElement, Router, routes} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js'; import {eventToPromise} from '../test_util.m.js';
diff --git a/chrome/updater/win/setup/setup.cc b/chrome/updater/win/setup/setup.cc index 258dc211..b688945 100644 --- a/chrome/updater/win/setup/setup.cc +++ b/chrome/updater/win/setup/setup.cc
@@ -176,6 +176,11 @@ AddComInterfacesWorkItems(key, versioned_dir->Append(kUpdaterExe), install_list.get()); + if (scope == UpdaterScope::kSystem) { + AddComServiceWorkItems(versioned_dir->Append(kUpdaterExe), + install_list.get()); + } + base::CommandLine run_updater_wake_command( versioned_dir->Append(kUpdaterExe)); run_updater_wake_command.AppendSwitch(kWakeSwitch);
diff --git a/chromecast/browser/accessibility/touch_exploration_manager.cc b/chromecast/browser/accessibility/touch_exploration_manager.cc index a7b12f9b..a66ca9cd 100644 --- a/chromecast/browser/accessibility/touch_exploration_manager.cc +++ b/chromecast/browser/accessibility/touch_exploration_manager.cc
@@ -65,11 +65,10 @@ // AccessibilityController::HandleAccessibilityGestore.) extensions::EventRouter* event_router = extensions::EventRouter::Get( shell::CastBrowserProcess::GetInstance()->browser_context()); - std::unique_ptr<base::ListValue> event_args = - std::make_unique<base::ListValue>(); - event_args->AppendString(ui::ToString(gesture)); - event_args->AppendInteger(location.x()); - event_args->AppendInteger(location.y()); + std::vector<base::Value> event_args; + event_args.push_back(base::Value(ui::ToString(gesture))); + event_args.push_back(base::Value(location.x())); + event_args.push_back(base::Value(location.y())); std::unique_ptr<extensions::Event> event(new extensions::Event( extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE, extensions::cast::api::accessibility_private::OnAccessibilityGesture::
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.cc b/chromecast/browser/extensions/cast_extensions_browser_client.cc index 7847aed..110fb91 100644 --- a/chromecast/browser/extensions/cast_extensions_browser_client.cc +++ b/chromecast/browser/extensions/cast_extensions_browser_client.cc
@@ -237,7 +237,7 @@ // Currently ignoring the dispatch_to_off_the_record_profiles attribute // as it is not necessary at the time std::unique_ptr<Event> event( - new Event(histogram_value, event_name, std::move(args))); + new Event(histogram_value, event_name, args->TakeList())); EventRouter::Get(browser_context_)->BroadcastEvent(std::move(event)); }
diff --git a/chromecast/common/BUILD.gn b/chromecast/common/BUILD.gn index 311e639..a5bb5e02 100644 --- a/chromecast/common/BUILD.gn +++ b/chromecast/common/BUILD.gn
@@ -84,6 +84,7 @@ "//chromecast/base:cast_version", "//chromecast/common/media", "//chromecast/common/mojom", + "//components/cast/common:constants", "//components/cdm/common:common", "//content/public/common", "//media:media_buildflags",
diff --git a/chromecast/common/DEPS b/chromecast/common/DEPS index 3f1ef85..63ba4c4 100644 --- a/chromecast/common/DEPS +++ b/chromecast/common/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/cdm/common", + "+components/cast/common", "+components/services/heap_profiling/public/cpp", "+components/url_matcher", "+components/version_info",
diff --git a/chromecast/common/cast_content_client.cc b/chromecast/common/cast_content_client.cc index 05277ab..ea10192 100644 --- a/chromecast/common/cast_content_client.cc +++ b/chromecast/common/cast_content_client.cc
@@ -19,6 +19,7 @@ #include "chromecast/base/cast_paths.h" #include "chromecast/base/version.h" #include "chromecast/chromecast_buildflags.h" +#include "components/cast/common/constants.h" #include "content/public/common/cdm_info.h" #include "content/public/common/user_agent.h" #include "media/base/media_switches.h" @@ -173,8 +174,8 @@ .c_str() #endif ); - return content::BuildUserAgentFromOSAndProduct(os_info, product) + - " CrKey/" CAST_BUILD_REVISION; + return content::BuildUserAgentFromOSAndProduct(os_info, product) + " CrKey/" + + kFrozenCrKeyValue; } CastContentClient::~CastContentClient() {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 2e83fff..ad0a2c2 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -13976.0.0 \ No newline at end of file +13977.0.0 \ No newline at end of file
diff --git a/components/BUILD.gn b/components/BUILD.gn index ee06de8..1b00597c0 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -11,7 +11,7 @@ import("//components/ui_devtools/devtools.gni") import("//extensions/buildflags/buildflags.gni") import("//media/media_options.gni") -import("//ppapi/buildflags/buildflags.gni") +import("//pdf/features.gni") import("//printing/buildflags/buildflags.gni") import("//rlz/buildflags/buildflags.gni") import("//testing/test.gni") @@ -517,7 +517,7 @@ ] } - if (enable_plugins) { + if (enable_pdf) { deps += [ "//components/pdf/renderer:unit_tests" ] } @@ -712,7 +712,7 @@ data += [ "$root_out_dir/Content Shell.app/" ] } - if (enable_plugins) { + if (enable_pdf) { sources += [ "pdf/browser/pdf_web_contents_helper_browsertest.cc", "pdf/renderer/pdf_accessibility_tree_browsertest.cc",
diff --git a/components/arc/session/connection_holder.h b/components/arc/session/connection_holder.h index 542b19fb..19f33fe 100644 --- a/components/arc/session/connection_holder.h +++ b/components/arc/session/connection_holder.h
@@ -6,7 +6,6 @@ #define COMPONENTS_ARC_SESSION_CONNECTION_HOLDER_H_ #include <memory> -#include <string> #include <type_traits> #include <utility>
diff --git a/components/assist_ranker/ranker_model_loader.h b/components/assist_ranker/ranker_model_loader.h index 392828f..e55fa9d9 100644 --- a/components/assist_ranker/ranker_model_loader.h +++ b/components/assist_ranker/ranker_model_loader.h
@@ -6,7 +6,6 @@ #define COMPONENTS_ASSIST_RANKER_RANKER_MODEL_LOADER_H_ #include <memory> -#include <string> #include "base/callback.h" #include "components/assist_ranker/ranker_model.h"
diff --git a/components/autofill/content/browser/webauthn/internal_authenticator_impl.h b/components/autofill/content/browser/webauthn/internal_authenticator_impl.h index f8509782..9811f10 100644 --- a/components/autofill/content/browser/webauthn/internal_authenticator_impl.h +++ b/components/autofill/content/browser/webauthn/internal_authenticator_impl.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include <memory> -#include <string> #include "base/macros.h" #include "components/autofill/core/browser/payments/internal_authenticator.h"
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc index 5536cc4..a4baf9f 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -98,6 +98,18 @@ *GetProfile(), *GetOriginalProfile(), locale_); } +bool AutofillSaveUpdateAddressProfileDelegateIOS::EditAccepted() { + RunSaveAddressProfilePromptCallback( + AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted); + return true; +} + +void AutofillSaveUpdateAddressProfileDelegateIOS::SetProfileRawInfo( + const ServerFieldType& type, + const std::u16string& data) { + profile_.SetRawInfo(type, data); +} + bool AutofillSaveUpdateAddressProfileDelegateIOS::Accept() { RunSaveAddressProfilePromptCallback( AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted);
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h index 35d9ad5..a360c41b0 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -59,6 +59,14 @@ base::flat_map<ServerFieldType, std::pair<std::u16string, std::u16string>> GetProfileDiff() const; + // Calls |RunSaveAddressProfilePromptCallback| with the kEditAccepted| + // decision. + virtual bool EditAccepted(); + + // Updates |profile_| |type| value to |data|. + void SetProfileRawInfo(const ServerFieldType& type, + const std::u16string& data); + const autofill::AutofillProfile* GetProfile() const; const autofill::AutofillProfile* GetOriginalProfile() const; void set_modal_is_shown_to_true() { modal_is_shown_ = true; }
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 8d3f0462..7f970d9 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -1479,7 +1479,8 @@ FillCreditCardForm(credit_card_query_id_, credit_card_form_, credit_card_field_, *credit_card, cvc); - if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD) { + if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD || + credit_card->record_type() == CreditCard::VIRTUAL_CARD) { credit_card_access_manager_->CacheUnmaskedCardInfo(*credit_card, cvc); } }
diff --git a/components/autofill/core/browser/form_parsing/autofill_scanner.h b/components/autofill/core/browser/form_parsing/autofill_scanner.h index 53179b4..52d90906 100644 --- a/components/autofill/core/browser/form_parsing/autofill_scanner.h +++ b/components/autofill/core/browser/form_parsing/autofill_scanner.h
@@ -8,7 +8,6 @@ #include <stddef.h> #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h b/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h index 8a016e0..d1ba2b5b 100644 --- a/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h +++ b/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
@@ -6,7 +6,6 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ #include <memory> -#include <string> #include "base/macros.h" #include "components/prefs/pref_change_registrar.h"
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc index 9176197..30226283 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -45,6 +45,9 @@ // Time to wait between multiple calls to GetUnmaskDetails(). constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min +// Suffix for server IDs in the cache indicating that a card is a virtual card. +const char kVirtualCardIdentifier[] = "_vcn"; + // Used for asynchronously waiting for |event| to be signaled. bool WaitForEvent(base::WaitableEvent* event) { event->declare_only_used_while_idle(); @@ -112,6 +115,20 @@ return unmasked_card_cache_.empty(); } +std::vector<const CachedServerCardInfo*> +CreditCardAccessManager::GetCachedUnmaskedCards() const { + std::vector<const CachedServerCardInfo*> unmasked_cards; + for (auto const& iter : unmasked_card_cache_) { + unmasked_cards.push_back(&iter.second); + } + return unmasked_cards; +} + +bool CreditCardAccessManager::IsCardPresentInUnmaskedCache( + const std::string& server_id) const { + return unmasked_card_cache_.find(server_id) != unmasked_card_cache_.end(); +} + bool CreditCardAccessManager::ServerCardsAvailable() { for (const CreditCard* credit_card : GetCreditCardsToSuggest()) { if (!IsLocalCard(credit_card)) @@ -259,14 +276,19 @@ } // If card has been previously unmasked, use cached data. + std::string identifier = card->record_type() == CreditCard::VIRTUAL_CARD + ? card->server_id() + kVirtualCardIdentifier + : card->server_id(); std::unordered_map<std::string, CachedServerCardInfo>::iterator it = - unmasked_card_cache_.find(card->server_id()); + unmasked_card_cache_.find(identifier); if (it != unmasked_card_cache_.end()) { // key is in cache accessor->OnCreditCardFetched(/*did_succeed=*/true, /*credit_card=*/&it->second.card, /*cvc=*/it->second.cvc); - base::UmaHistogramCounts1000("Autofill.UsedCachedServerCard", - ++it->second.cache_uses); + std::string metrics_name = card->record_type() == CreditCard::VIRTUAL_CARD + ? "Autofill.UsedCachedVirtualCard" + : "Autofill.UsedCachedServerCard"; + base::UmaHistogramCounts1000(metrics_name, ++it->second.cache_uses); return; } @@ -370,9 +392,13 @@ void CreditCardAccessManager::CacheUnmaskedCardInfo(const CreditCard& card, const std::u16string& cvc) { - DCHECK_EQ(card.record_type(), CreditCard::FULL_SERVER_CARD); - CachedServerCardInfo card_info = {card, cvc, 0}; - unmasked_card_cache_[card.server_id()] = card_info; + DCHECK(card.record_type() == CreditCard::FULL_SERVER_CARD || + card.record_type() == CreditCard::VIRTUAL_CARD); + std::string identifier = card.record_type() == CreditCard::VIRTUAL_CARD + ? card.server_id() + kVirtualCardIdentifier + : card.server_id(); + CachedServerCardInfo card_info = {card, cvc, /*cache_uses=*/0}; + unmasked_card_cache_[identifier] = card_info; } UnmaskAuthFlowType CreditCardAccessManager::GetAuthenticationType(
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h index ca6add9..bd86db5 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager.h +++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -131,6 +131,14 @@ // TODO(crbug/1069929): Add browsertests for this. void CacheUnmaskedCardInfo(const CreditCard& card, const std::u16string& cvc); + // Return the info for the server cards present in the + // |unamsked_cards_cache_|. + std::vector<const CachedServerCardInfo*> GetCachedUnmaskedCards() const; + + // Returns true if a |unmasked_cards_cache| contains an entry for the card + // with |server_id|. + bool IsCardPresentInUnmaskedCache(const std::string& server_id) const; + CreditCardCVCAuthenticator* GetOrCreateCVCAuthenticator(); #if !defined(OS_IOS)
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc index 7163b7e..b83c1b5 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -80,9 +80,13 @@ namespace { const char kTestGUID[] = "00000000-0000-0000-0000-000000000001"; +const char kTestGUID2[] = "00000000-0000-0000-0000-000000000002"; const char kTestNumber[] = "4234567890123456"; // Visa +const char kTestNumber2[] = "5454545454545454"; const char16_t kTestNumber16[] = u"4234567890123456"; const char16_t kTestCvc16[] = u"123"; +const char kTestServerId[] = "server_id_1"; +const char kTestServerId2[] = "server_id_2"; #if !defined(OS_IOS) const char kTestCvc[] = "123"; @@ -218,7 +222,8 @@ void CreateServerCard(std::string guid, std::string number = std::string(), - bool masked = true) { + bool masked = true, + std::string server_id = std::string()) { CreditCard server_card = CreditCard(); test::SetCreditCardInfo(&server_card, "Elvis Presley", number.c_str(), test::NextMonth().c_str(), test::NextYear().c_str(), @@ -226,7 +231,7 @@ server_card.set_guid(guid); server_card.set_record_type(masked ? CreditCard::MASKED_SERVER_CARD : CreditCard::FULL_SERVER_CARD); - + server_card.set_server_id(server_id); personal_data_manager_.AddServerCreditCard(server_card); } @@ -1855,10 +1860,58 @@ credit_card_access_manager_->FetchCreditCard(masked_card, accessor_->GetWeakPtr()); histogram_tester.ExpectBucketCount("Autofill.UsedCachedServerCard", 1, 1); - credit_card_access_manager_->FetchCreditCard(masked_card, accessor_->GetWeakPtr()); histogram_tester.ExpectBucketCount("Autofill.UsedCachedServerCard", 2, 1); + + // Create a virtual card. + CreditCard virtual_card = CreditCard(); + test::SetCreditCardInfo(&virtual_card, "Elvis Presley", kTestNumber, + test::NextMonth().c_str(), test::NextYear().c_str(), + "1"); + virtual_card.set_record_type(CreditCard::VIRTUAL_CARD); + credit_card_access_manager_->CacheUnmaskedCardInfo(virtual_card, kTestCvc16); + + // Mocks that user selects the virtual card option of the masked card. + masked_card->set_record_type(CreditCard::VIRTUAL_CARD); + credit_card_access_manager_->FetchCreditCard(masked_card, + accessor_->GetWeakPtr()); + + histogram_tester.ExpectBucketCount("Autofill.UsedCachedVirtualCard", 1, 1); +} + +TEST_F(CreditCardAccessManagerTest, GetCachedUnmaskedCards) { + // Assert that there are no cards cached initially. + EXPECT_EQ(0U, credit_card_access_manager_->GetCachedUnmaskedCards().size()); + + CreateServerCard(kTestGUID, kTestNumber, /*masked=*/false, kTestServerId); + CreateServerCard(kTestGUID2, kTestNumber2, /*masked=*/true, kTestServerId2); + // Add a card to the cache. + CreditCard* unmasked_card = + credit_card_access_manager_->GetCreditCard(kTestGUID); + credit_card_access_manager_->CacheUnmaskedCardInfo(*unmasked_card, + kTestCvc16); + + // Verify that only the card added to the cache is returned. + ASSERT_EQ(1U, credit_card_access_manager_->GetCachedUnmaskedCards().size()); + EXPECT_EQ(*unmasked_card, + credit_card_access_manager_->GetCachedUnmaskedCards()[0]->card); +} + +TEST_F(CreditCardAccessManagerTest, IsCardPresentInUnmaskedCache) { + CreateServerCard(kTestGUID, kTestNumber, /*masked=*/false, kTestServerId); + CreateServerCard(kTestGUID2, kTestNumber2, /*masked=*/true, kTestServerId2); + // Add a card to the cache. + CreditCard* unmasked_card = + credit_card_access_manager_->GetCreditCard(kTestGUID); + credit_card_access_manager_->CacheUnmaskedCardInfo(*unmasked_card, + kTestCvc16); + + // Verify that only one card is present in the cache. + EXPECT_TRUE(credit_card_access_manager_->IsCardPresentInUnmaskedCache( + unmasked_card->server_id())); + EXPECT_FALSE(credit_card_access_manager_->IsCardPresentInUnmaskedCache( + credit_card_access_manager_->GetCreditCard(kTestGUID2)->server_id())); } } // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_base.cc b/components/autofill/core/browser/strike_database_integrator_base.cc index b7109648..6d63e2ee 100644 --- a/components/autofill/core/browser/strike_database_integrator_base.cc +++ b/components/autofill/core/browser/strike_database_integrator_base.cc
@@ -140,6 +140,10 @@ } std::vector<std::string> expired_keys; for (auto entry : strike_database_->GetStrikeCache()) { + // Only consider keys from the current strike database integrator. + if (strike_database_->GetPrefixFromKey(entry.first) != GetProjectPrefix()) { + continue; + } if (GetEntryAge(entry.second) > GetExpiryTimeDelta().value()) { if (strike_database_->GetStrikes(entry.first) > 0) { expired_keys.push_back(entry.first);
diff --git a/components/autofill/core/browser/strike_database_integrator_base.h b/components/autofill/core/browser/strike_database_integrator_base.h index 81e9b5b..af0c194 100644 --- a/components/autofill/core/browser/strike_database_integrator_base.h +++ b/components/autofill/core/browser/strike_database_integrator_base.h
@@ -95,19 +95,21 @@ FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest, StrikeDatabaseEmptyOnAutofillRemoveEverything); FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, - NonExpiringStrikesDoNotExpire); - FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, - RemoveExpiredStrikesTest); + ClearStrikesForKeys); FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, GetKeyForStrikeDatabaseIntegratorUniqueIdTest); FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, - RemoveExpiredStrikesUniqueIdTest); + IdFromKey); + FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, + NonExpiringStrikesDoNotExpire); + FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, + RemoveExpiredStrikesOnlyConsidersCurrentIntegrator); + FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, + RemoveExpiredStrikesTest); FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, RemoveExpiredStrikesTestLogsUMA); FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, - IdFromKey); - FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, - ClearStrikesForKeys); + RemoveExpiredStrikesUniqueIdTest); friend class SaveCardInfobarEGTestHelper; friend class StrikeDatabaseTest; friend class StrikeDatabaseTester;
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc index 80dd5d33..a3e5b90 100644 --- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc +++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
@@ -8,7 +8,6 @@ namespace autofill { -const char kProjectPrefix[] = "StrikeDatabaseIntegratorTest"; const int kMaxStrikesLimit = 6; StrikeDatabaseIntegratorTestStrikeDatabase:: @@ -26,11 +25,21 @@ } StrikeDatabaseIntegratorTestStrikeDatabase:: + StrikeDatabaseIntegratorTestStrikeDatabase( + StrikeDatabase* strike_database, + absl::optional<base::TimeDelta> expiry_time_delta, + std::string& project_prefix) + : StrikeDatabaseIntegratorTestStrikeDatabase(strike_database, + expiry_time_delta) { + project_prefix_ = project_prefix; +} + +StrikeDatabaseIntegratorTestStrikeDatabase:: ~StrikeDatabaseIntegratorTestStrikeDatabase() = default; std::string StrikeDatabaseIntegratorTestStrikeDatabase::GetProjectPrefix() const { - return kProjectPrefix; + return project_prefix_; } int StrikeDatabaseIntegratorTestStrikeDatabase::GetMaxStrikesLimit() const {
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h index 1c132af..33053e76 100644 --- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h +++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
@@ -23,6 +23,12 @@ absl::optional<base::TimeDelta> expiry_time_delta); explicit StrikeDatabaseIntegratorTestStrikeDatabase( StrikeDatabase* strike_database); + // This constructor initializes the TestStrikeDatabase with a non-default + // project prefix. + StrikeDatabaseIntegratorTestStrikeDatabase( + StrikeDatabase* strike_database, + absl::optional<base::TimeDelta> expiry_time_delta, + std::string& project_prefix); ~StrikeDatabaseIntegratorTestStrikeDatabase() override; absl::optional<size_t> GetMaximumEntries() const override; @@ -42,6 +48,7 @@ absl::optional<size_t> maximum_entries_ = 10; absl::optional<size_t> maximum_entries_after_cleanup_ = 5; + std::string project_prefix_ = "StrikeDatabaseIntegratorTest"; }; } // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc index 8cb5f99..5182966 100644 --- a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc +++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
@@ -206,6 +206,38 @@ 11, 1); } +// This test verifies correctness of http://crbug/1206176. +TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest, + RemoveExpiredStrikesOnlyConsidersCurrentIntegrator) { + autofill::TestAutofillClock test_clock; + test_clock.SetNow(AutofillClock::Now()); + // Create a second test integrator, but with a different project prefix name, + // and whose strikes explicitly do not expire. + std::string other_project_prefix = "DifferentProjectPrefix"; + std::unique_ptr<StrikeDatabaseIntegratorTestStrikeDatabase> + other_strike_database = + std::make_unique<StrikeDatabaseIntegratorTestStrikeDatabase>( + strike_database_service_.get(), + /*expiry_time_micros=*/absl::nullopt, other_project_prefix); + + // Add a strike to both integrators. + strike_database_->AddStrike(); + EXPECT_EQ(1, strike_database_->GetStrikes()); + other_strike_database->AddStrike(); + EXPECT_EQ(1, other_strike_database->GetStrikes()); + + // Advance clock to past expiry time for |strike_database_|. + test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() + + base::TimeDelta::FromMicroseconds(1)); + + // Attempt to expire strikes. Only |strike_database_|'s keys should be + // affected. + strike_database_->RemoveExpiredStrikes(); + other_strike_database->RemoveExpiredStrikes(); + EXPECT_EQ(0, strike_database_->GetStrikes()); + EXPECT_EQ(1, other_strike_database->GetStrikes()); +} + TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest, GetKeyForStrikeDatabaseIntegratorUniqueIdTest) { strike_database_->SetUniqueIdsRequired(true);
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc index 340ca9b..bc82b4f 100644 --- a/components/autofill/core/common/autofill_payments_features.cc +++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -131,6 +131,12 @@ const base::Feature kAutofillSaveCardInfobarEditSupport{ "AutofillSaveCardInfobarEditSupport", base::FEATURE_ENABLED_BY_DEFAULT}; +// When enabled, the entire PAN and the CVC details of the unmasked cached card +// will be shown in the manual filling view. +const base::Feature kAutofillShowUnmaskedCachedCardInManualFillingView{ + "AutofillShowUnmaskedCachedCardInManualFillingView", + base::FEATURE_DISABLED_BY_DEFAULT}; + // When enabled, suggestions with offers will be shown at the top. const base::Feature kAutofillSortSuggestionsBasedOnOfferPresence{ "AutofillSortSuggestionsBasedOnOfferPresence",
diff --git a/components/autofill/core/common/autofill_payments_features.h b/components/autofill/core/common/autofill_payments_features.h index e8bbfb93..e21a996a 100644 --- a/components/autofill/core/common/autofill_payments_features.h +++ b/components/autofill/core/common/autofill_payments_features.h
@@ -36,6 +36,7 @@ extern const base::Feature kAutofillParseMerchantPromoCodeFields; extern const base::Feature kAutofillSaveCardDismissOnNavigation; extern const base::Feature kAutofillSaveCardInfobarEditSupport; +extern const base::Feature kAutofillShowUnmaskedCachedCardInManualFillingView; extern const base::Feature kAutofillSortSuggestionsBasedOnOfferPresence; extern const base::Feature kAutofillSuggestVirtualCardsOnlyOnFullFormDetection; extern const base::Feature kAutofillSuppressCreditCardSaveForAssistant;
diff --git a/components/autofill_assistant/browser/actions/stopwatch.h b/components/autofill_assistant/browser/actions/stopwatch.h index cd399cc..64f7fd2a 100644 --- a/components/autofill_assistant/browser/actions/stopwatch.h +++ b/components/autofill_assistant/browser/actions/stopwatch.h
@@ -6,7 +6,6 @@ #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_STOPWATCH_H_ #include <ostream> -#include <string> #include "base/time/time.h"
diff --git a/components/autofill_assistant/browser/actions/use_address_action.h b/components/autofill_assistant/browser/actions/use_address_action.h index f818308..2c145c1 100644 --- a/components/autofill_assistant/browser/actions/use_address_action.h +++ b/components/autofill_assistant/browser/actions/use_address_action.h
@@ -6,7 +6,6 @@ #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_USE_ADDRESS_ACTION_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/autofill_assistant/browser/element_area.h b/components/autofill_assistant/browser/element_area.h index 01c78e1..2652fa0 100644 --- a/components/autofill_assistant/browser/element_area.h +++ b/components/autofill_assistant/browser/element_area.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ELEMENT_AREA_H_ #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ELEMENT_AREA_H_ -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/blocklist/opt_out_blocklist/opt_out_blocklist_item.h b/components/blocklist/opt_out_blocklist/opt_out_blocklist_item.h index 303709b..158260d 100644 --- a/components/blocklist/opt_out_blocklist/opt_out_blocklist_item.h +++ b/components/blocklist/opt_out_blocklist/opt_out_blocklist_item.h
@@ -10,7 +10,6 @@ #include <map> #include <memory> #include <queue> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/browsing_data/content/browsing_data_helper.cc b/components/browsing_data/content/browsing_data_helper.cc index 9431308..dcb4dc62 100644 --- a/components/browsing_data/content/browsing_data_helper.cc +++ b/components/browsing_data/content/browsing_data_helper.cc
@@ -81,6 +81,7 @@ void RemoveSiteIsolationData(PrefService* prefs) { prefs->ClearPref(site_isolation::prefs::kUserTriggeredIsolatedOrigins); + prefs->ClearPref(site_isolation::prefs::kWebTriggeredIsolatedOrigins); // Note that this does not clear these sites from the in-memory map in // ChildProcessSecurityPolicy, since that is not supported at runtime. That // list of isolated sites is not directly exposed to users, though, and
diff --git a/components/browsing_data/content/cookie_helper.h b/components/browsing_data/content/cookie_helper.h index 99bd6da1..799e975 100644 --- a/components/browsing_data/content/cookie_helper.h +++ b/components/browsing_data/content/cookie_helper.h
@@ -8,7 +8,6 @@ #include <stddef.h> #include <map> -#include <string> #include "base/callback.h" #include "base/callback_forward.h"
diff --git a/components/browsing_data/content/database_helper.h b/components/browsing_data/content/database_helper.h index 25c7983..d3f05a0 100644 --- a/components/browsing_data/content/database_helper.h +++ b/components/browsing_data/content/database_helper.h
@@ -10,7 +10,6 @@ #include <list> #include <set> -#include <string> #include "base/callback_forward.h" #include "base/macros.h"
diff --git a/components/browsing_data/content/indexed_db_helper.h b/components/browsing_data/content/indexed_db_helper.h index 428c6fa..86820bb0 100644 --- a/components/browsing_data/content/indexed_db_helper.h +++ b/components/browsing_data/content/indexed_db_helper.h
@@ -9,7 +9,6 @@ #include <list> #include <set> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/browsing_data/core/counters/browsing_data_counter.h b/components/browsing_data/core/counters/browsing_data_counter.h index e809b0074..9d8aa95e 100644 --- a/components/browsing_data/core/counters/browsing_data_counter.h +++ b/components/browsing_data/core/counters/browsing_data_counter.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/cast/common/BUILD.gn b/components/cast/common/BUILD.gn new file mode 100644 index 0000000..4eef367 --- /dev/null +++ b/components/cast/common/BUILD.gn
@@ -0,0 +1,10 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("constants") { + sources = [ + "constants.cc", + "constants.h", + ] +}
diff --git a/components/cast/common/constants.cc b/components/cast/common/constants.cc new file mode 100644 index 0000000..c662d65 --- /dev/null +++ b/components/cast/common/constants.cc
@@ -0,0 +1,11 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cast/common/constants.h" + +namespace chromecast { + +const char kFrozenCrKeyValue[] = "1.56.500000"; + +} // namespace chromecast
diff --git a/components/cast/common/constants.h b/components/cast/common/constants.h new file mode 100644 index 0000000..affcdc2 --- /dev/null +++ b/components/cast/common/constants.h
@@ -0,0 +1,15 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CAST_COMMON_CONSTANTS_H_ +#define COMPONENTS_CAST_COMMON_CONSTANTS_H_ + +namespace chromecast { + +// See internal b/187823385 for details. +extern const char kFrozenCrKeyValue[]; + +} // namespace chromecast + +#endif // COMPONENTS_CAST_COMMON_CONSTANTS_H_
diff --git a/components/cast_channel/cast_socket.h b/components/cast_channel/cast_socket.h index fd3ad68d..bdf05e2 100644 --- a/components/cast_channel/cast_socket.h +++ b/components/cast_channel/cast_socket.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include <queue> -#include <string> #include "base/cancelable_callback.h" #include "base/gtest_prod_util.h"
diff --git a/components/cast_channel/logger.h b/components/cast_channel/logger.h index f4d91e8..a4b9c8e8 100644 --- a/components/cast_channel/logger.h +++ b/components/cast_channel/logger.h
@@ -9,7 +9,6 @@ #include <map> #include <memory> -#include <string> #include "base/macros.h" #include "base/memory/ref_counted.h"
diff --git a/components/client_hints/browser/client_hints.h b/components/client_hints/browser/client_hints.h index 92fe05e..57d192d 100644 --- a/components/client_hints/browser/client_hints.h +++ b/components/client_hints/browser/client_hints.h
@@ -6,7 +6,6 @@ #define COMPONENTS_CLIENT_HINTS_BROWSER_CLIENT_HINTS_H_ #include <memory> -#include <string> #include "base/memory/ref_counted.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h b/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h index 515f849db57..0aa7660f 100644 --- a/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h +++ b/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
@@ -9,7 +9,6 @@ #include <map> #include <memory> -#include <string> #include "base/macros.h" #include "base/time/time.h"
diff --git a/components/content_settings/core/browser/content_settings_provider.h b/components/content_settings/core/browser/content_settings_provider.h index a87df22..744c6f1d 100644 --- a/components/content_settings/core/browser/content_settings_provider.h +++ b/components/content_settings/core/browser/content_settings_provider.h
@@ -8,7 +8,6 @@ #define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_PROVIDER_H_ #include <memory> -#include <string> #include "base/values.h" #include "components/content_settings/core/browser/content_settings_rule.h"
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.h b/components/cronet/android/cronet_bidirectional_stream_adapter.h index e76db766..7934fb2 100644 --- a/components/cronet/android/cronet_bidirectional_stream_adapter.h +++ b/components/cronet/android/cronet_bidirectional_stream_adapter.h
@@ -8,7 +8,6 @@ #include <jni.h> #include <memory> -#include <string> #include "base/android/jni_android.h" #include "base/android/jni_array.h"
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h index 18d93f1..311278ae 100644 --- a/components/cronet/android/cronet_url_request_context_adapter.h +++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -9,7 +9,6 @@ #include <stdint.h> #include <memory> -#include <string> #include "base/android/scoped_java_ref.h" #include "base/callback.h"
diff --git a/components/cronet/android/test/url_request_intercepting_job_factory.h b/components/cronet/android/test/url_request_intercepting_job_factory.h index 9a46ed96..8cdc925 100644 --- a/components/cronet/android/test/url_request_intercepting_job_factory.h +++ b/components/cronet/android/test/url_request_intercepting_job_factory.h
@@ -6,7 +6,6 @@ #define COMPONENTS_CRONET_ANDROID_TEST_URL_REQUEST_INTERCEPTING_JOB_FACTORY_H_ #include <memory> -#include <string> #include "base/compiler_specific.h" #include "base/macros.h"
diff --git a/components/cronet/native/upload_data_sink.h b/components/cronet/native/upload_data_sink.h index 3a893b6..d233761a 100644 --- a/components/cronet/native/upload_data_sink.h +++ b/components/cronet/native/upload_data_sink.h
@@ -6,7 +6,6 @@ #define COMPONENTS_CRONET_NATIVE_UPLOAD_DATA_SINK_H_ #include <memory> -#include <string> #include "base/macros.h" #include "base/synchronization/lock.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h index f505cd3..ab60b27 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/dom_distiller/core/dom_distiller_service.h b/components/dom_distiller/core/dom_distiller_service.h index 97d7674..121bf8d 100644 --- a/components/dom_distiller/core/dom_distiller_service.h +++ b/components/dom_distiller/core/dom_distiller_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_SERVICE_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/download/internal/background_service/entry_utils.h b/components/download/internal/background_service/entry_utils.h index a519d75..b251a5b1 100644 --- a/components/download/internal/background_service/entry_utils.h +++ b/components/download/internal/background_service/entry_utils.h
@@ -7,7 +7,6 @@ #include <map> #include <set> -#include <string> #include <vector> #include "components/download/internal/background_service/model.h"
diff --git a/components/download/internal/background_service/file_monitor.h b/components/download/internal/background_service/file_monitor.h index 11fd4dd6..050cb3b 100644 --- a/components/download/internal/background_service/file_monitor.h +++ b/components/download/internal/background_service/file_monitor.h
@@ -7,7 +7,6 @@ #include <memory> #include <set> -#include <string> #include <vector> #include "components/download/internal/background_service/model.h"
diff --git a/components/download/internal/background_service/file_monitor_impl.h b/components/download/internal/background_service/file_monitor_impl.h index 34ee780..3df902b 100644 --- a/components/download/internal/background_service/file_monitor_impl.h +++ b/components/download/internal/background_service/file_monitor_impl.h
@@ -9,7 +9,6 @@ #include <memory> #include <set> -#include <string> #include <vector> #include "base/files/file_path.h"
diff --git a/components/embedder_support/android/delegate/color_chooser_android.h b/components/embedder_support/android/delegate/color_chooser_android.h index 71ae29e..05da5e36 100644 --- a/components/embedder_support/android/delegate/color_chooser_android.h +++ b/components/embedder_support/android/delegate/color_chooser_android.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_COLOR_CHOOSER_ANDROID_H_ #define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_COLOR_CHOOSER_ANDROID_H_ -#include <string> #include <vector> #include "base/android/jni_android.h"
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index 6cc34314..7c9e0d2 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -292,14 +292,13 @@ DISALLOW_COPY_AND_ASSIGN(CustomWindowStateDelegate); }; -void CloseAllTransientChildren(aura::Window* window) { - // Deleting a window may delete other transient children, so - // delete them by popping from the list. - for (;;) { - auto list = wm::GetTransientChildren(window); - if (list.empty()) - return; - wm::RemoveTransientChild(window, *list.begin()); +void CloseAllShellSurfaceTransientChildren(aura::Window* window) { + // Deleting a window may delete other transient children. Remove other shell + // surface bases first so they don't get deleted. + auto list = wm::GetTransientChildren(window); + for (size_t i = 0; i < list.size(); ++i) { + if (GetShellSurfaceBaseForWindow(list[i])) + wm::RemoveTransientChild(window, list[i]); } } @@ -355,8 +354,9 @@ if (widget_) { widget_->GetNativeWindow()->RemoveObserver(this); widget_->RemoveObserver(this); - // Remove transient children so they are not automatically destroyed. - CloseAllTransientChildren(widget_->GetNativeWindow()); + // Remove transient children which are shell surfaces so they are not + // automatically destroyed. + CloseAllShellSurfaceTransientChildren(widget_->GetNativeWindow()); if (widget_->IsVisible()) widget_->Hide(); widget_->CloseNow(); @@ -806,8 +806,9 @@ // Hide widget before surface is destroyed. This allows hide animations to // run using the current surface contents. if (widget_) { - // Remove transient children so they are not automatically hidden. - CloseAllTransientChildren(widget_->GetNativeWindow()); + // Remove transient children which are shell surfaces so they are not + // automatically hidden. + CloseAllShellSurfaceTransientChildren(widget_->GetNativeWindow()); widget_->Hide(); }
diff --git a/components/feed/core/v2/public/feed_service.cc b/components/feed/core/v2/public/feed_service.cc index d0c01ef..19855883 100644 --- a/components/feed/core/v2/public/feed_service.cc +++ b/components/feed/core/v2/public/feed_service.cc
@@ -134,7 +134,7 @@ bool IsEulaAccepted() override { return eula_notifier_.IsEulaAccepted() || base::CommandLine::ForCurrentProcess()->HasSwitch( - "feedv2-accept-eula"); + "feed-screenshot-mode"); } bool IsOffline() override { return net::NetworkChangeNotifier::IsOffline(); } DisplayMetrics GetDisplayMetrics() override {
diff --git a/components/feed/core/v2/tasks/load_stream_from_store_task.h b/components/feed/core/v2/tasks/load_stream_from_store_task.h index 0a5ee54..2385e5e 100644 --- a/components/feed/core/v2/tasks/load_stream_from_store_task.h +++ b/components/feed/core/v2/tasks/load_stream_from_store_task.h
@@ -6,7 +6,6 @@ #define COMPONENTS_FEED_CORE_V2_TASKS_LOAD_STREAM_FROM_STORE_TASK_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/gcm_driver/account_tracker.h b/components/gcm_driver/account_tracker.h index b89cc872..1a78a07 100644 --- a/components/gcm_driver/account_tracker.h +++ b/components/gcm_driver/account_tracker.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <vector> #include "base/observer_list.h"
diff --git a/components/heavy_ad_intervention/heavy_ad_service.h b/components/heavy_ad_intervention/heavy_ad_service.h index 1c1c9409..7a795d1 100644 --- a/components/heavy_ad_intervention/heavy_ad_service.h +++ b/components/heavy_ad_intervention/heavy_ad_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_HEAVY_AD_INTERVENTION_HEAVY_AD_SERVICE_H_ #include <memory> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/history/content/browser/download_conversions.h b/components/history/content/browser/download_conversions.h index 1482efa..274d4d8 100644 --- a/components/history/content/browser/download_conversions.h +++ b/components/history/content/browser/download_conversions.h
@@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/download_item.h"
diff --git a/components/history/core/browser/top_sites_database.h b/components/history/core/browser/top_sites_database.h index 14a720a6..6078cd1 100644 --- a/components/history/core/browser/top_sites_database.h +++ b/components/history/core/browser/top_sites_database.h
@@ -6,7 +6,6 @@ #define COMPONENTS_HISTORY_CORE_BROWSER_TOP_SITES_DATABASE_H_ #include <map> -#include <string> #include "base/gtest_prod_util.h" #include "base/macros.h"
diff --git a/components/history/core/test/history_service_test_util.h b/components/history/core/test/history_service_test_util.h index d3f94c3..4ab848d 100644 --- a/components/history/core/test/history_service_test_util.h +++ b/components/history/core/test/history_service_test_util.h
@@ -6,7 +6,6 @@ #define COMPONENTS_HISTORY_CORE_TEST_HISTORY_SERVICE_TEST_UTIL_H_ #include <memory> -#include <string> #include "base/macros.h"
diff --git a/components/infobars/android/infobar_android.h b/components/infobars/android/infobar_android.h index cf08fe9a..38881e8 100644 --- a/components/infobars/android/infobar_android.h +++ b/components/infobars/android/infobar_android.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_INFOBARS_ANDROID_INFOBAR_ANDROID_H_ #define COMPONENTS_INFOBARS_ANDROID_INFOBAR_ANDROID_H_ -#include <string> - #include "base/android/scoped_java_ref.h" #include "base/callback.h" #include "base/macros.h"
diff --git a/components/js_injection/browser/web_message_reply_proxy.h b/components/js_injection/browser/web_message_reply_proxy.h index 9a09c02..2eb52975 100644 --- a/components/js_injection/browser/web_message_reply_proxy.h +++ b/components/js_injection/browser/web_message_reply_proxy.h
@@ -5,9 +5,6 @@ #ifndef COMPONENTS_JS_INJECTION_BROWSER_WEB_MESSAGE_REPLY_PROXY_H_ #define COMPONENTS_JS_INJECTION_BROWSER_WEB_MESSAGE_REPLY_PROXY_H_ -#include <string> - - namespace js_injection { struct WebMessage;
diff --git a/components/js_injection/common/origin_matcher_mojom_traits.h b/components/js_injection/common/origin_matcher_mojom_traits.h index 873d2cb..b4c02553 100644 --- a/components/js_injection/common/origin_matcher_mojom_traits.h +++ b/components/js_injection/common/origin_matcher_mojom_traits.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_JS_INJECTION_COMMON_ORIGIN_MATCHER_MOJOM_TRAITS_H_ #define COMPONENTS_JS_INJECTION_COMMON_ORIGIN_MATCHER_MOJOM_TRAITS_H_ -#include <string> #include <vector> #include "components/js_injection/common/origin_matcher.h"
diff --git a/components/live_caption/BUILD.gn b/components/live_caption/BUILD.gn index 0ef5c49..748a8e7 100644 --- a/components/live_caption/BUILD.gn +++ b/components/live_caption/BUILD.gn
@@ -2,27 +2,29 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("live_caption") { - sources = [ - "views/caption_bubble.cc", - "views/caption_bubble.h", - "views/caption_bubble_model.cc", - "views/caption_bubble_model.h", - ] +if (!is_android) { + static_library("live_caption") { + sources = [ + "views/caption_bubble.cc", + "views/caption_bubble.h", + "views/caption_bubble_model.cc", + "views/caption_bubble_model.h", + ] - deps = [ - "//base", - "//components/strings", - "//components/vector_icons", - "//third_party/re2", - "//ui/accessibility", - "//ui/base", - "//ui/gfx", - "//ui/native_theme", - "//ui/strings:ui_strings_grit", - "//ui/views", - ] -} + deps = [ + "//base", + "//components/strings", + "//components/vector_icons", + "//third_party/re2", + "//ui/accessibility", + "//ui/base", + "//ui/gfx", + "//ui/native_theme", + "//ui/strings:ui_strings_grit", + "//ui/views", + ] + } +} # !is_android source_set("constants") { sources = [
diff --git a/components/live_caption/pref_names.cc b/components/live_caption/pref_names.cc index 703f8f5..b596aad 100644 --- a/components/live_caption/pref_names.cc +++ b/components/live_caption/pref_names.cc
@@ -6,6 +6,7 @@ namespace prefs { +#if !defined(ANDROID) // Whether the Live Caption feature is enabled. const char kLiveCaptionEnabled[] = "accessibility.captions.live_caption_enabled"; @@ -13,5 +14,34 @@ // The language to use with the Live Caption feature. const char kLiveCaptionLanguageCode[] = "accessibility.captions.live_caption_language"; +#endif // !defined(ANDROID) + +// String indicating the size of the captions text as a percentage. +const char kAccessibilityCaptionsTextSize[] = + "accessibility.captions.text_size"; + +// String indicating the font of the captions text. +const char kAccessibilityCaptionsTextFont[] = + "accessibility.captions.text_font"; + +// Comma-separated string indicating the RGB values of the captions text color. +const char kAccessibilityCaptionsTextColor[] = + "accessibility.captions.text_color"; + +// Integer indicating the opacity of the captions text from 0 - 100. +const char kAccessibilityCaptionsTextOpacity[] = + "accessibility.captions.text_opacity"; + +// Comma-separated string indicating the RGB values of the background color. +const char kAccessibilityCaptionsBackgroundColor[] = + "accessibility.captions.background_color"; + +// CSS string indicating the shadow of the captions text. +const char kAccessibilityCaptionsTextShadow[] = + "accessibility.captions.text_shadow"; + +// Integer indicating the opacity of the captions text background from 0 - 100. +const char kAccessibilityCaptionsBackgroundOpacity[] = + "accessibility.captions.background_opacity"; } // namespace prefs
diff --git a/components/live_caption/pref_names.h b/components/live_caption/pref_names.h index 56b66f1a..3f93d11a 100644 --- a/components/live_caption/pref_names.h +++ b/components/live_caption/pref_names.h
@@ -7,8 +7,23 @@ namespace prefs { +// Live Caption is not available on Android, so exclude these unneeded +// kLiveCaption* prefs. +#if !defined(ANDROID) extern const char kLiveCaptionEnabled[]; extern const char kLiveCaptionLanguageCode[]; +#endif // !defined(ANDROID) + +// These kAccessibilityCaptions* caption style prefs are used on Android +// (though their primary use is for Live Caption, which is why they are housed +// within this live_caption component instead of somewhere more generic). +extern const char kAccessibilityCaptionsTextSize[]; +extern const char kAccessibilityCaptionsTextFont[]; +extern const char kAccessibilityCaptionsTextColor[]; +extern const char kAccessibilityCaptionsTextOpacity[]; +extern const char kAccessibilityCaptionsBackgroundColor[]; +extern const char kAccessibilityCaptionsTextShadow[]; +extern const char kAccessibilityCaptionsBackgroundOpacity[]; } // namespace prefs
diff --git a/components/lookalikes/core/BUILD.gn b/components/lookalikes/core/BUILD.gn index fccb480..c46ad6f7 100644 --- a/components/lookalikes/core/BUILD.gn +++ b/components/lookalikes/core/BUILD.gn
@@ -14,6 +14,8 @@ "//base", "//components/pref_registry", "//components/prefs:prefs", + "//components/reputation/core:core", + "//components/reputation/core:proto", "//components/security_interstitials/core", "//components/security_state/core:features", "//components/strings", @@ -36,6 +38,7 @@ deps = [ ":core", ":features", + "//components/reputation/core", "//net:test_support", "//testing/gtest", ]
diff --git a/components/lookalikes/core/DEPS b/components/lookalikes/core/DEPS index a3c048b..33c4e65 100644 --- a/components/lookalikes/core/DEPS +++ b/components/lookalikes/core/DEPS
@@ -3,4 +3,6 @@ # should not be introduced. "-content", "-ios/web", + # components/reputation contains the lookalike (safety tips) component. + "+components/reputation/core", ]
diff --git a/components/lookalikes/core/features.cc b/components/lookalikes/core/features.cc index 3eb15692..3d1fb0c 100644 --- a/components/lookalikes/core/features.cc +++ b/components/lookalikes/core/features.cc
@@ -9,7 +9,7 @@ // Note: this flag is ignored on iOS. See lookalike_url_util.cc. const base::Feature kDetectTargetEmbeddingLookalikes{ - "TargetEmbeddingLookalikes", base::FEATURE_DISABLED_BY_DEFAULT}; + "TargetEmbeddingLookalikes", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kLookalikeInterstitialForPunycode{ "LookalikeInterstitialForPunycode", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/lookalikes/core/lookalike_url_util.cc b/components/lookalikes/core/lookalike_url_util.cc index 55965fd..a3e5695 100644 --- a/components/lookalikes/core/lookalike_url_util.cc +++ b/components/lookalikes/core/lookalike_url_util.cc
@@ -27,6 +27,7 @@ #include "base/values.h" #include "build/build_config.h" #include "components/lookalikes/core/features.h" +#include "components/reputation/core/safety_tips_config.h" #include "components/security_interstitials/core/pref_names.h" #include "components/security_state/core/features.h" #include "components/url_formatter/spoof_checks/common_words/common_words_util.h" @@ -285,7 +286,8 @@ // Returns whether the e2LD of the provided domain is a common word (e.g. // weather.com, ask.com). Target embeddings of these domains are often false // positives (e.g. "super-best-fancy-hotels.com" isn't spoofing "hotels.com"). -bool UsesCommonWord(const DomainInfo& domain) { +bool UsesCommonWord(const reputation::SafetyTipsConfig* config_proto, + const DomainInfo& domain) { // kDomainsPermittedInEndEmbeddings are based on domains with common words, // but they should not be excluded here (and instead are checked later). for (auto* permitted_ending : kDomainsPermittedInEndEmbeddings) { @@ -300,7 +302,13 @@ return true; } - // Also check the local lists. + // Search for words in the component-provided word list. + if (reputation::IsCommonWordInConfigProto(config_proto, + domain.domain_without_registry)) { + return true; + } + + // Search for words in the local word lists. for (auto* common_word : kLocalAdditionalCommonWords) { if (domain.domain_without_registry == common_word) { return true; @@ -369,8 +377,9 @@ const DomainInfo& embedded_target, const base::span<const base::StringPiece>& subdomain_span, const LookalikeTargetAllowlistChecker& in_target_allowlist, - const std::string& embedding_domain) { - return UsesCommonWord(embedded_target) || + const std::string& embedding_domain, + const reputation::SafetyTipsConfig* config_proto) { + return UsesCommonWord(config_proto, embedded_target) || ASubdomainIsAllowlisted(subdomain_span, in_target_allowlist) || IsEmbeddingItself(subdomain_span, embedding_domain) || IsCrossTLDMatch(embedded_target, embedding_domain) || @@ -614,6 +623,7 @@ const DomainInfo& navigated_domain, const std::vector<DomainInfo>& engaged_sites, const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, std::string* matched_domain, LookalikeUrlMatchType* match_type) { DCHECK(!navigated_domain.domain_and_registry.empty()); @@ -674,7 +684,7 @@ TargetEmbeddingType embedding_type = GetTargetEmbeddingType(navigated_domain.hostname, engaged_sites, - in_target_allowlist, matched_domain); + in_target_allowlist, config_proto, matched_domain); if (embedding_type == TargetEmbeddingType::kSafetyTip) { *match_type = LookalikeUrlMatchType::kTargetEmbeddingForSafetyTips; return true; @@ -723,6 +733,37 @@ const std::string& hostname, const std::vector<DomainInfo>& engaged_sites, const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, + std::string* safe_hostname) { + // Because of how target embeddings are detected (i.e. by sweeping the URL + // from back to front), we're guaranteed to find tail-embedding before other + // target embedding. Tail embedding triggers a safety tip, but interstitials + // are more important than safety tips, so if we find a safety tippable + // embedding with SearchForEmbeddings, go search again not permitting safety + // tips to see if we can also find an interstitiallable embedding. + auto result = SearchForEmbeddings( + hostname, engaged_sites, in_target_allowlist, config_proto, + /*safety_tips_allowed=*/true, safe_hostname); + if (result == TargetEmbeddingType::kSafetyTip) { + std::string no_st_safe_hostname; + auto no_st_result = SearchForEmbeddings( + hostname, engaged_sites, in_target_allowlist, config_proto, + /*safety_tips_allowed=*/false, &no_st_safe_hostname); + if (no_st_result == TargetEmbeddingType::kNone) { + return result; + } + *safe_hostname = no_st_safe_hostname; + return no_st_result; + } + return result; +} + +TargetEmbeddingType SearchForEmbeddings( + const std::string& hostname, + const std::vector<DomainInfo>& engaged_sites, + const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, + bool safety_tips_allowed, std::string* safe_hostname) { const std::string embedding_domain = GetETLDPlusOne(hostname); const std::vector<base::StringPiece> hostname_tokens = @@ -762,7 +803,8 @@ if (no_separator_dominfo.domain_without_registry.length() > kMinE2LDLengthForTargetEmbedding && !IsAllowedToBeEmbedded(no_separator_dominfo, no_separator_tokens, - in_target_allowlist, embedding_domain)) { + in_target_allowlist, embedding_domain, + config_proto)) { *safe_hostname = embedded_target; return TargetEmbeddingType::kInterstitial; } @@ -791,9 +833,17 @@ for (auto& engaged_site : engaged_sites) { if (engaged_site.hostname == embedded_dominfo.hostname && !IsAllowedToBeEmbedded(embedded_dominfo, span, in_target_allowlist, - embedding_domain)) { + embedding_domain, config_proto)) { *safe_hostname = engaged_site.hostname; - return TargetEmbeddingType::kInterstitial; + // Tail-embedding (e.g. evil-google.com, where the embedding happens + // at the very end of the hostname) is a safety tip, but only when + // safety tips are allowed. If it's tail embedding but we can't create + // a safety tip, keep looking. Non-tail-embeddings are interstitials. + if (end != static_cast<int>(hostname_tokens.size())) { + return TargetEmbeddingType::kInterstitial; + } else if (safety_tips_allowed) { + return TargetEmbeddingType::kSafetyTip; + } // else keep searching. } } } @@ -803,8 +853,17 @@ if (DoesETLDPlus1MatchTopDomainOrEngagedSite( etld_check_dominfo, engaged_sites, safe_hostname) && !IsAllowedToBeEmbedded(etld_check_dominfo, etld_check_span, - in_target_allowlist, embedding_domain)) { - return TargetEmbeddingType::kInterstitial; + in_target_allowlist, embedding_domain, + config_proto)) { + // Tail-embedding (e.g. evil-google.com, where the embedding happens at + // the very end of the hostname) is a safety tip, but only when safety + // tips are allowed. If it's tail embedding but we can't create a safety + // tip, keep looking. Non-tail-embeddings are interstitials. + if (end != static_cast<int>(hostname_tokens.size())) { + return TargetEmbeddingType::kInterstitial; + } else if (safety_tips_allowed) { + return TargetEmbeddingType::kSafetyTip; + } // else keep searching. } } return TargetEmbeddingType::kNone;
diff --git a/components/lookalikes/core/lookalike_url_util.h b/components/lookalikes/core/lookalike_url_util.h index 4882419..e5a8ba87 100644 --- a/components/lookalikes/core/lookalike_url_util.h +++ b/components/lookalikes/core/lookalike_url_util.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" +#include "components/reputation/core/safety_tips.pb.h" #include "components/url_formatter/url_formatter.h" #include "url/gurl.h" @@ -162,31 +163,33 @@ const DomainInfo& navigated_domain, const std::vector<DomainInfo>& engaged_sites, const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, std::string* matched_domain, LookalikeUrlMatchType* match_type); void RecordUMAFromMatchType(LookalikeUrlMatchType match_type); // Checks to see if a URL is a target embedding lookalike. This function sets -// |safe_hostname| to the url of the embedded target domain. -// At the moment we consider the following cases as Target Embedding: -// example-google.com-site.com, example.google.com-site.com, -// example-google-info-site.com, example.google.com.site.com, -// example-googlé.com-site.com where the embedded target is google.com. We -// detect embeddings of top 500 domains and engaged domains. However, to reduce -// false positives, we do not protect domains that are shorter than 7 characters -// long (e.g. com.ru). -// This function checks possible targets against |in_target_allowlist| to skip -// permitted embeddings. -// If no target embedding is found, the return value will be set to |kNonw|. -// When the target is embedded with another TLD instead of its actual TLD, it -// should trigger a Safety Tip when the embedded TLD is a ccTLD. In this -// situation, return value will be |kSafetyTip|. All the other triggers will -// result in a |kInterstitial| return value. +// |safe_hostname| to the url of the embedded target domain. See the unit tests +// for what qualifies as target embedding. TargetEmbeddingType GetTargetEmbeddingType( const std::string& hostname, const std::vector<DomainInfo>& engaged_sites, const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, + std::string* safe_hostname); + +// Same as GetTargetEmbeddingType, but explicitly state whether or not a safety +// tip is permitted via |safety_tips_allowed|. Safety tips are presently only +// used for tail embedding (e.g. "evil-google.com"). This function may return +// kSafetyTip preferentially to kInterstitial -- call with !safety_tips_allowed +// if you're interested in determining if there's *also* an interstitial. +TargetEmbeddingType SearchForEmbeddings( + const std::string& hostname, + const std::vector<DomainInfo>& engaged_sites, + const LookalikeTargetAllowlistChecker& in_target_allowlist, + const reputation::SafetyTipsConfig* config_proto, + bool safety_tips_allowed, std::string* safe_hostname); // Returns true if a navigation to an IDN should be blocked.
diff --git a/components/lookalikes/core/lookalike_url_util_unittest.cc b/components/lookalikes/core/lookalike_url_util_unittest.cc index 4062ea9..e7b52ca 100644 --- a/components/lookalikes/core/lookalike_url_util_unittest.cc +++ b/components/lookalikes/core/lookalike_url_util_unittest.cc
@@ -7,8 +7,22 @@ #include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "components/lookalikes/core/features.h" +#include "components/reputation/core/safety_tip_test_utils.h" +#include "components/reputation/core/safety_tips_config.h" #include "testing/gtest/include/gtest/gtest.h" +std::string TargetEmbeddingTypeToString(TargetEmbeddingType type) { + switch (type) { + case TargetEmbeddingType::kNone: + return "kNone"; + case TargetEmbeddingType::kInterstitial: + return "kInterstitial"; + case TargetEmbeddingType::kSafetyTip: + return "kSafetyTip"; + } + NOTREACHED(); +} + TEST(LookalikeUrlUtilTest, IsEditDistanceAtMostOne) { const struct TestCase { const wchar_t* domain; @@ -139,7 +153,7 @@ const TargetEmbeddingType expected_type; }; -TEST(LookalikeUrlUtilTest, TargetEmbeddingTest) { +TEST(LookalikeUrlUtilTest, TargetEmbedding) { const std::vector<DomainInfo> kEngagedSites = { GetDomainInfo(GURL("https://highengagement.com")), GetDomainInfo(GURL("https://highengagement.inthesubdomain.com")), @@ -278,12 +292,15 @@ {"google.com.google.com", "", TargetEmbeddingType::kNone}, {"www.google.com.google.com", "", TargetEmbeddingType::kNone}, - // Detect embeddings at the end of the domain, too. - {"www-google.com", "google.com", TargetEmbeddingType::kInterstitial}, + // Detect embeddings at the end of the domain, too, but as a Safety Tip. + {"www-google.com", "google.com", TargetEmbeddingType::kSafetyTip}, {"www-highengagement.com", "highengagement.com", - TargetEmbeddingType::kInterstitial}, + TargetEmbeddingType::kSafetyTip}, {"subdomain-highengagement.com", "subdomain.highengagement.com", - TargetEmbeddingType::kInterstitial}, + TargetEmbeddingType::kSafetyTip}, + // If the match duplicates the TLD, it's not quite tail-embedding. + {"google-com.com", "google.com", TargetEmbeddingType::kInterstitial}, + // If there are multiple options, it should choose the more severe one. {"google-com.google-com.com", "google.com", TargetEmbeddingType::kInterstitial}, {"subdomain.google-com.google-com.com", "google.com", @@ -300,14 +317,17 @@ // works for domains on the list, but not for others. {"office.com-foo.com", "office.com", TargetEmbeddingType::kInterstitial}, {"example-office.com", "", TargetEmbeddingType::kNone}, - {"example-google.com", "google.com", TargetEmbeddingType::kInterstitial}, + {"example-google.com", "google.com", TargetEmbeddingType::kSafetyTip}, }; + reputation::InitializeBlankLookalikeAllowlistForTesting(); + auto* config_proto = reputation::GetSafetyTipsRemoteConfigProto(); + for (auto& test_case : kTestCases) { std::string safe_hostname; TargetEmbeddingType embedding_type = GetTargetEmbeddingType( test_case.hostname, kEngagedSites, - base::BindRepeating(&IsGoogleScholar), &safe_hostname); + base::BindRepeating(&IsGoogleScholar), config_proto, &safe_hostname); if (test_case.expected_type != TargetEmbeddingType::kNone) { EXPECT_EQ(safe_hostname, test_case.expected_safe_host) << test_case.hostname << " should trigger on " @@ -315,19 +335,43 @@ << (safe_hostname.empty() ? "it didn't trigger at all." : "triggered on " + safe_hostname); EXPECT_EQ(embedding_type, test_case.expected_type) - << test_case.hostname << " should trigger on " + << test_case.hostname << " should trigger " + << TargetEmbeddingTypeToString(test_case.expected_type) << " against " << test_case.expected_safe_host << " but it returned " - << (embedding_type == TargetEmbeddingType::kNone - ? "kNone." - : "something unexpected"); + << TargetEmbeddingTypeToString(embedding_type); } else { EXPECT_EQ(embedding_type, TargetEmbeddingType::kNone) - << test_case.hostname << " unexpectedly triggered on " + << test_case.hostname << " unexpectedly triggered " + << TargetEmbeddingTypeToString(embedding_type) << " against " << safe_hostname; } } } +TEST(LookalikeUrlUtilTest, TargetEmbeddingIgnoresComponentWordlist) { + const std::vector<DomainInfo> kEngagedSites = { + GetDomainInfo(GURL("https://commonword.com")), + GetDomainInfo(GURL("https://uncommonword.com")), + }; + + reputation::SetSafetyTipAllowlistPatterns({}, {}, {"commonword"}); + auto* config_proto = reputation::GetSafetyTipsRemoteConfigProto(); + TargetEmbeddingType embedding_type; + std::string safe_hostname; + + // Engaged sites using uncommon words are still blocked. + embedding_type = GetTargetEmbeddingType( + "uncommonword.com.evil.com", kEngagedSites, + base::BindRepeating(&IsGoogleScholar), config_proto, &safe_hostname); + EXPECT_EQ(embedding_type, TargetEmbeddingType::kInterstitial); + + // But engaged sites using common words are not blocked. + embedding_type = GetTargetEmbeddingType( + "commonword.com.evil.com", kEngagedSites, + base::BindRepeating(&IsGoogleScholar), config_proto, &safe_hostname); + EXPECT_EQ(embedding_type, TargetEmbeddingType::kNone); +} + struct GetETLDPlusOneTestCase { const std::string hostname; const std::string expected_etldp1;
diff --git a/components/media_control/renderer/media_playback_options.h b/components/media_control/renderer/media_playback_options.h index f355d74..54d536f 100644 --- a/components/media_control/renderer/media_playback_options.h +++ b/components/media_control/renderer/media_playback_options.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_MEDIA_CONTROL_RENDERER_MEDIA_PLAYBACK_OPTIONS_H_ #define COMPONENTS_MEDIA_CONTROL_RENDERER_MEDIA_PLAYBACK_OPTIONS_H_ -#include <string> #include <vector> #include "base/callback_forward.h"
diff --git a/components/media_router/browser/media_router_dialog_controller.h b/components/media_router/browser/media_router_dialog_controller.h index 009b2cc..ac6880fc 100644 --- a/components/media_router/browser/media_router_dialog_controller.h +++ b/components/media_router/browser/media_router_dialog_controller.h
@@ -6,7 +6,6 @@ #define COMPONENTS_MEDIA_ROUTER_BROWSER_MEDIA_ROUTER_DIALOG_CONTROLLER_H_ #include <memory> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/media_router/browser/route_message_observer.h b/components/media_router/browser/route_message_observer.h index 8c2452d..675b503 100644 --- a/components/media_router/browser/route_message_observer.h +++ b/components/media_router/browser/route_message_observer.h
@@ -7,7 +7,6 @@ #include <stdint.h> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/metrics/file_metrics_provider.h b/components/metrics/file_metrics_provider.h index f5fbb8a4..fe78275 100644 --- a/components/metrics/file_metrics_provider.h +++ b/components/metrics/file_metrics_provider.h
@@ -7,7 +7,6 @@ #include <list> #include <memory> -#include <string> #include "base/callback_forward.h" #include "base/files/file_path.h"
diff --git a/components/metrics/library_support/histogram_manager.h b/components/metrics/library_support/histogram_manager.h index 331eca0..1465284 100644 --- a/components/metrics/library_support/histogram_manager.h +++ b/components/metrics/library_support/histogram_manager.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include <memory> -#include <string> #include <vector> #include "base/lazy_instance.h"
diff --git a/components/metrics/metrics_log_manager.h b/components/metrics/metrics_log_manager.h index 88d8fe2..123a186 100644 --- a/components/metrics/metrics_log_manager.h +++ b/components/metrics/metrics_log_manager.h
@@ -8,7 +8,6 @@ #include <stddef.h> #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/metrics/structured/persistent_proto.h b/components/metrics/structured/persistent_proto.h index e73941cc..8f73a44 100644 --- a/components/metrics/structured/persistent_proto.h +++ b/components/metrics/structured/persistent_proto.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_ #define COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_ -#include <string> - #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h"
diff --git a/components/metrics/structured/structured_metrics_provider.h b/components/metrics/structured/structured_metrics_provider.h index 4be682a..d7d6b87 100644 --- a/components/metrics/structured/structured_metrics_provider.h +++ b/components/metrics/structured/structured_metrics_provider.h
@@ -6,7 +6,6 @@ #define COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_PROVIDER_H_ #include <memory> -#include <string> #include <vector> #include "base/files/file_path.h"
diff --git a/components/nacl/renderer/file_downloader.h b/components/nacl/renderer/file_downloader.h index 3760c38..1ed94f1 100644 --- a/components/nacl/renderer/file_downloader.h +++ b/components/nacl/renderer/file_downloader.h
@@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/callback.h" #include "base/files/file.h" #include "components/nacl/renderer/ppb_nacl_private.h"
diff --git a/components/no_state_prefetch/browser/no_state_prefetch_manager.h b/components/no_state_prefetch/browser/no_state_prefetch_manager.h index 13616c0..40346fe6 100644 --- a/components/no_state_prefetch/browser/no_state_prefetch_manager.h +++ b/components/no_state_prefetch/browser/no_state_prefetch_manager.h
@@ -9,7 +9,6 @@ #include <memory> #include <set> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/ntp_snippets/category_rankers/constant_category_ranker.h b/components/ntp_snippets/category_rankers/constant_category_ranker.h index 258e1045..3307f8b 100644 --- a/components/ntp_snippets/category_rankers/constant_category_ranker.h +++ b/components/ntp_snippets/category_rankers/constant_category_ranker.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CONSTANT_CATEGORY_RANKER_H_ #define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CONSTANT_CATEGORY_RANKER_H_ -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h index 3558ffb..35aa46a1 100644 --- a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h +++ b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
@@ -7,7 +7,6 @@ #include <memory> #include <set> -#include <string> #include <utility> #include <vector>
diff --git a/components/ntp_tiles/icon_cacher_impl.h b/components/ntp_tiles/icon_cacher_impl.h index 768c076..96e7a72 100644 --- a/components/ntp_tiles/icon_cacher_impl.h +++ b/components/ntp_tiles/icon_cacher_impl.h
@@ -7,7 +7,6 @@ #include <memory> #include <set> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/offline_pages/core/background/request_queue.h b/components/offline_pages/core/background/request_queue.h index e55e1f6b..2bd0b69 100644 --- a/components/offline_pages/core/background/request_queue.h +++ b/components/offline_pages/core/background/request_queue.h
@@ -9,7 +9,6 @@ #include <memory> #include <set> -#include <string> #include <utility> #include <vector>
diff --git a/components/offline_pages/core/offline_page_archive_publisher.h b/components/offline_pages/core/offline_page_archive_publisher.h index 5d90657..cea4b63 100644 --- a/components/offline_pages/core/offline_page_archive_publisher.h +++ b/components/offline_pages/core/offline_page_archive_publisher.h
@@ -6,7 +6,6 @@ #define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGE_ARCHIVE_PUBLISHER_H_ #include <cstdint> -#include <string> #include "base/callback.h" #include "base/files/file_path.h"
diff --git a/components/offline_pages/core/offline_page_test_archive_publisher.h b/components/offline_pages/core/offline_page_test_archive_publisher.h index 40e141a0..55a8202a 100644 --- a/components/offline_pages/core/offline_page_test_archive_publisher.h +++ b/components/offline_pages/core/offline_page_test_archive_publisher.h
@@ -6,7 +6,6 @@ #define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGE_TEST_ARCHIVE_PUBLISHER_H_ #include <cstdint> -#include <string> #include "base/callback.h" #include "components/offline_pages/core/offline_page_archive_publisher.h"
diff --git a/components/offline_pages/core/prefetch/tasks/remove_url_task.h b/components/offline_pages/core/prefetch/tasks/remove_url_task.h index e5f4c22..d1f3f1de 100644 --- a/components/offline_pages/core/prefetch/tasks/remove_url_task.h +++ b/components/offline_pages/core/prefetch/tasks/remove_url_task.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TASKS_REMOVE_URL_TASK_H_ #define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TASKS_REMOVE_URL_TASK_H_ -#include <string> #include <vector> #include "base/memory/weak_ptr.h"
diff --git a/components/omnibox/browser/bookmark_provider.h b/components/omnibox/browser/bookmark_provider.h index 6af51eac..7740b18 100644 --- a/components/omnibox/browser/bookmark_provider.h +++ b/components/omnibox/browser/bookmark_provider.h
@@ -7,8 +7,6 @@ #include <stddef.h> -#include <string> - #include "base/gtest_prod_util.h" #include "components/bookmarks/browser/titled_url_match.h" #include "components/omnibox/browser/autocomplete_input.h"
diff --git a/components/omnibox/browser/omnibox_controller.h b/components/omnibox/browser/omnibox_controller.h index c7c3b67..2650532b 100644 --- a/components/omnibox/browser/omnibox_controller.h +++ b/components/omnibox/browser/omnibox_controller.h
@@ -6,7 +6,6 @@ #define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_CONTROLLER_H_ #include <memory> -#include <string> #include "base/compiler_specific.h" #include "components/omnibox/browser/autocomplete_controller.h"
diff --git a/components/on_load_script_injector/browser/on_load_script_injector_host.h b/components/on_load_script_injector/browser/on_load_script_injector_host.h index 21356eb..bbe65a7 100644 --- a/components/on_load_script_injector/browser/on_load_script_injector_host.h +++ b/components/on_load_script_injector/browser/on_load_script_injector_host.h
@@ -6,7 +6,6 @@ #define COMPONENTS_ON_LOAD_SCRIPT_INJECTOR_BROWSER_ON_LOAD_SCRIPT_INJECTOR_HOST_H_ #include <map> -#include <string> #include <vector> #include "base/memory/read_only_shared_memory_region.h"
diff --git a/components/optimization_guide/content/browser/page_text_observer.h b/components/optimization_guide/content/browser/page_text_observer.h index 95e780a..4e6ed3e 100644 --- a/components/optimization_guide/content/browser/page_text_observer.h +++ b/components/optimization_guide/content/browser/page_text_observer.h
@@ -7,7 +7,6 @@ #include <stdint.h> #include <set> -#include <string> #include "base/callback.h" #include "base/memory/weak_ptr.h"
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc index 8d8fc21..4fcb18fa 100644 --- a/components/optimization_guide/core/optimization_guide_features.cc +++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -36,8 +36,13 @@ "OptimizationHintsFetching", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kRemoteOptimizationGuideFetchingAnonymousDataConsent{ - "OptimizationHintsFetchingAnonymousDataConsent", - base::FEATURE_ENABLED_BY_DEFAULT}; + "OptimizationHintsFetchingAnonymousDataConsent", +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else // !defined(OS_ANDROID) + base::FEATURE_DISABLED_BY_DEFAULT +#endif // defined(OS_ANDROID) +}; // Enables performance info in the context menu and fetching from a remote // Optimization Guide Service.
diff --git a/components/page_info/android/BUILD.gn b/components/page_info/android/BUILD.gn index 9b56e29..a18094a 100644 --- a/components/page_info/android/BUILD.gn +++ b/components/page_info/android/BUILD.gn
@@ -32,21 +32,6 @@ android_resources("java_resources") { sources = [ - "java/res/drawable-hdpi/pageinfo_bad.png", - "java/res/drawable-hdpi/pageinfo_good.png", - "java/res/drawable-hdpi/pageinfo_warning.png", - "java/res/drawable-mdpi/pageinfo_bad.png", - "java/res/drawable-mdpi/pageinfo_good.png", - "java/res/drawable-mdpi/pageinfo_warning.png", - "java/res/drawable-xhdpi/pageinfo_bad.png", - "java/res/drawable-xhdpi/pageinfo_good.png", - "java/res/drawable-xhdpi/pageinfo_warning.png", - "java/res/drawable-xxhdpi/pageinfo_bad.png", - "java/res/drawable-xxhdpi/pageinfo_good.png", - "java/res/drawable-xxhdpi/pageinfo_warning.png", - "java/res/drawable-xxxhdpi/pageinfo_bad.png", - "java/res/drawable-xxxhdpi/pageinfo_good.png", - "java/res/drawable-xxxhdpi/pageinfo_warning.png", "java/res/drawable/ic_tune_24dp.xml", "java/res/drawable/page_info_bg.xml", "java/res/layout/connection_info.xml",
diff --git a/components/page_info/android/java/res/drawable-hdpi/pageinfo_bad.png b/components/page_info/android/java/res/drawable-hdpi/pageinfo_bad.png deleted file mode 100644 index cd802be..0000000 --- a/components/page_info/android/java/res/drawable-hdpi/pageinfo_bad.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-hdpi/pageinfo_good.png b/components/page_info/android/java/res/drawable-hdpi/pageinfo_good.png deleted file mode 100644 index 3aa5349..0000000 --- a/components/page_info/android/java/res/drawable-hdpi/pageinfo_good.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-hdpi/pageinfo_warning.png b/components/page_info/android/java/res/drawable-hdpi/pageinfo_warning.png deleted file mode 100644 index 841b01f..0000000 --- a/components/page_info/android/java/res/drawable-hdpi/pageinfo_warning.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-mdpi/pageinfo_bad.png b/components/page_info/android/java/res/drawable-mdpi/pageinfo_bad.png deleted file mode 100644 index 92ce9bdc..0000000 --- a/components/page_info/android/java/res/drawable-mdpi/pageinfo_bad.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-mdpi/pageinfo_good.png b/components/page_info/android/java/res/drawable-mdpi/pageinfo_good.png deleted file mode 100644 index 60678e1..0000000 --- a/components/page_info/android/java/res/drawable-mdpi/pageinfo_good.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-mdpi/pageinfo_warning.png b/components/page_info/android/java/res/drawable-mdpi/pageinfo_warning.png deleted file mode 100644 index 002da07..0000000 --- a/components/page_info/android/java/res/drawable-mdpi/pageinfo_warning.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_bad.png b/components/page_info/android/java/res/drawable-xhdpi/pageinfo_bad.png deleted file mode 100644 index b9a0354..0000000 --- a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_bad.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_good.png b/components/page_info/android/java/res/drawable-xhdpi/pageinfo_good.png deleted file mode 100644 index 11f8c32..0000000 --- a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_good.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_warning.png b/components/page_info/android/java/res/drawable-xhdpi/pageinfo_warning.png deleted file mode 100644 index 918c09c..0000000 --- a/components/page_info/android/java/res/drawable-xhdpi/pageinfo_warning.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_bad.png b/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_bad.png deleted file mode 100644 index b259de5..0000000 --- a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_bad.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_good.png b/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_good.png deleted file mode 100644 index 6c23d7c8..0000000 --- a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_good.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_warning.png b/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_warning.png deleted file mode 100644 index 57b86b3b..0000000 --- a/components/page_info/android/java/res/drawable-xxhdpi/pageinfo_warning.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_bad.png b/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_bad.png deleted file mode 100644 index 1c27dfd..0000000 --- a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_bad.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_good.png b/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_good.png deleted file mode 100644 index d11f3d7..0000000 --- a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_good.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_warning.png b/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_warning.png deleted file mode 100644 index 19d1ee2..0000000 --- a/components/page_info/android/java/res/drawable-xxxhdpi/pageinfo_warning.png +++ /dev/null Binary files differ
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoFeatures.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoFeatures.java index b477a07..340be5a 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoFeatures.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoFeatures.java
@@ -19,14 +19,12 @@ public class PageInfoFeatures extends Features { public static final String PAGE_INFO_DISCOVERABILITY_NAME = "PageInfoDiscoverability"; public static final String PAGE_INFO_HISTORY_NAME = "PageInfoHistory"; - public static final String PAGE_INFO_V2_NAME = "PageInfoV2"; // This list must be kept in sync with kFeaturesExposedToJava in page_info_features.cc. public static final PageInfoFeatures PAGE_INFO_DISCOVERABILITY = new PageInfoFeatures(0, PAGE_INFO_DISCOVERABILITY_NAME); public static final PageInfoFeatures PAGE_INFO_HISTORY = new PageInfoFeatures(1, PAGE_INFO_HISTORY_NAME); - public static final PageInfoFeatures PAGE_INFO_V2 = new PageInfoFeatures(2, PAGE_INFO_V2_NAME); private final int mOrdinal;
diff --git a/components/page_info/android/page_info_controller_android.cc b/components/page_info/android/page_info_controller_android.cc index fff0218..404e75c 100644 --- a/components/page_info/android/page_info_controller_android.cc +++ b/components/page_info/android/page_info_controller_android.cc
@@ -200,8 +200,7 @@ // setting should show up in Page Info is in ShouldShowPermission in // page_info.cc. return permission.default_setting; - } else if (permission.type == ContentSettingsType::JAVASCRIPT && - base::FeatureList::IsEnabled(page_info::kPageInfoV2)) { + } else if (permission.type == ContentSettingsType::JAVASCRIPT) { // The javascript content setting should show up if it is blocked globally // to give users an easy way to create exceptions. return permission.default_setting;
diff --git a/components/page_info/android/page_info_features.cc b/components/page_info/android/page_info_features.cc index db517b7..96bd37f4 100644 --- a/components/page_info/android/page_info_features.cc +++ b/components/page_info/android/page_info_features.cc
@@ -17,7 +17,6 @@ const base::Feature* kFeaturesExposedToJava[] = { &kPageInfoDiscoverability, &kPageInfoHistory, - &kPageInfoV2, }; } // namespace
diff --git a/components/page_info/features.cc b/components/page_info/features.cc index 9d9f81da..e86dbf9 100644 --- a/components/page_info/features.cc +++ b/components/page_info/features.cc
@@ -14,7 +14,6 @@ base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kPageInfoHistory{"PageInfoHistory", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kPageInfoV2{"PageInfoV2", base::FEATURE_ENABLED_BY_DEFAULT}; #endif #if !defined(OS_ANDROID)
diff --git a/components/page_info/features.h b/components/page_info/features.h index b25fe47c..1f70655 100644 --- a/components/page_info/features.h +++ b/components/page_info/features.h
@@ -18,8 +18,6 @@ extern const base::Feature kPageInfoDiscoverability; // Enables the history sub page for Page Info. extern const base::Feature kPageInfoHistory; -// Enables the second version of the Page Info View. -extern const base::Feature kPageInfoV2; #endif #if !defined(OS_ANDROID)
diff --git a/components/page_info/page_info_ui.cc b/components/page_info/page_info_ui.cc index d34cecf..f28a5de 100644 --- a/components/page_info/page_info_ui.cc +++ b/components/page_info/page_info_ui.cc
@@ -279,10 +279,6 @@ std::unique_ptr<PageInfoUI::SecurityDescription> PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const { - bool page_info_v2_enabled = false; -#if defined(OS_ANDROID) - page_info_v2_enabled = base::FeatureList::IsEnabled(page_info::kPageInfoV2); -#endif switch (identity_info.safe_browsing_status) { case PageInfo::SAFE_BROWSING_STATUS_NONE: break; @@ -329,73 +325,97 @@ } switch (identity_info.identity_status) { - case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE: #if defined(OS_ANDROID) + case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE: return CreateSecurityDescription(SecuritySummaryColor::GREEN, 0, IDS_PAGE_INFO_INTERNAL_PAGE, SecurityDescriptionType::INTERNAL); -#else - // Internal pages on desktop have their own UI implementations which - // should never call this function. - NOTREACHED(); - FALLTHROUGH; -#endif case PageInfo::SITE_IDENTITY_STATUS_EV_CERT: - FALLTHROUGH; case PageInfo::SITE_IDENTITY_STATUS_CERT: - FALLTHROUGH; case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT: switch (identity_info.connection_status) { case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE: return CreateSecurityDescription( - SecuritySummaryColor::RED, - page_info_v2_enabled ? IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT - : IDS_PAGE_INFO_NOT_SECURE_SUMMARY, + SecuritySummaryColor::RED, IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT, IDS_PAGE_INFO_NOT_SECURE_DETAILS, SecurityDescriptionType::CONNECTION); case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION: return CreateSecurityDescription( SecuritySummaryColor::RED, - page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT - : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT, IDS_PAGE_INFO_NOT_SECURE_DETAILS, SecurityDescriptionType::CONNECTION); case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE: return CreateSecurityDescription( SecuritySummaryColor::RED, - page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT - : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT, IDS_PAGE_INFO_MIXED_CONTENT_DETAILS, SecurityDescriptionType::CONNECTION); case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS: return CreateSecurityDescription( SecuritySummaryColor::RED, - page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT - : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT, IDS_PAGE_INFO_LEGACY_TLS_DETAILS, SecurityDescriptionType::CONNECTION); default: - int secure_details = IDS_PAGE_INFO_SECURE_DETAILS; -#if defined(OS_ANDROID) - if (page_info_v2_enabled) { - // Do not show details for secure connections. - secure_details = 0; - } -#endif - return CreateSecurityDescription( - SecuritySummaryColor::GREEN, IDS_PAGE_INFO_SECURE_SUMMARY, - secure_details, SecurityDescriptionType::CONNECTION); + // Do not show details for secure connections. + return CreateSecurityDescription(SecuritySummaryColor::GREEN, + IDS_PAGE_INFO_SECURE_SUMMARY, 0, + SecurityDescriptionType::CONNECTION); } case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM: case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN: case PageInfo::SITE_IDENTITY_STATUS_NO_CERT: default: - return CreateSecurityDescription( - SecuritySummaryColor::RED, - page_info_v2_enabled ? IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT - : IDS_PAGE_INFO_NOT_SECURE_SUMMARY, - IDS_PAGE_INFO_NOT_SECURE_DETAILS, - SecurityDescriptionType::CONNECTION); + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT, + IDS_PAGE_INFO_NOT_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); +#else + case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE: + // Internal pages on desktop have their own UI implementations which + // should never call this function. + NOTREACHED(); + FALLTHROUGH; + case PageInfo::SITE_IDENTITY_STATUS_EV_CERT: + case PageInfo::SITE_IDENTITY_STATUS_CERT: + case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT: + switch (identity_info.connection_status) { + case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE: + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_NOT_SECURE_SUMMARY, + IDS_PAGE_INFO_NOT_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); + case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION: + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_NOT_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); + case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE: + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_MIXED_CONTENT_DETAILS, + SecurityDescriptionType::CONNECTION); + case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS: + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY, + IDS_PAGE_INFO_LEGACY_TLS_DETAILS, + SecurityDescriptionType::CONNECTION); + default: + return CreateSecurityDescription(SecuritySummaryColor::GREEN, + IDS_PAGE_INFO_SECURE_SUMMARY, + IDS_PAGE_INFO_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); + } + case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM: + case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN: + case PageInfo::SITE_IDENTITY_STATUS_NO_CERT: + default: + return CreateSecurityDescription(SecuritySummaryColor::RED, + IDS_PAGE_INFO_NOT_SECURE_SUMMARY, + IDS_PAGE_INFO_NOT_SECURE_DETAILS, + SecurityDescriptionType::CONNECTION); +#endif } } @@ -525,95 +545,39 @@ #if defined(OS_ANDROID) // static int PageInfoUI::GetIdentityIconID(PageInfo::SiteIdentityStatus status) { - if (base::FeatureList::IsEnabled(page_info::kPageInfoV2)) { - switch (status) { - case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN: - case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE: - case PageInfo::SITE_IDENTITY_STATUS_CERT: - case PageInfo::SITE_IDENTITY_STATUS_EV_CERT: - return IDR_PAGEINFO_GOOD_V2; - case PageInfo::SITE_IDENTITY_STATUS_NO_CERT: - case PageInfo::SITE_IDENTITY_STATUS_ERROR: - case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT: - case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM: - return IDR_PAGEINFO_BAD_V2; - } - - return 0; - } - - int resource_id = IDR_PAGEINFO_INFO; switch (status) { case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN: case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE: - break; case PageInfo::SITE_IDENTITY_STATUS_CERT: case PageInfo::SITE_IDENTITY_STATUS_EV_CERT: - resource_id = IDR_PAGEINFO_GOOD; - break; + return IDR_PAGEINFO_GOOD; case PageInfo::SITE_IDENTITY_STATUS_NO_CERT: - resource_id = IDR_PAGEINFO_WARNING_MAJOR; - break; case PageInfo::SITE_IDENTITY_STATUS_ERROR: - resource_id = IDR_PAGEINFO_BAD; - break; case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT: - resource_id = IDR_PAGEINFO_ENTERPRISE_MANAGED; - break; case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM: - resource_id = IDR_PAGEINFO_WARNING_MINOR; - break; - default: - NOTREACHED(); - break; + return IDR_PAGEINFO_BAD; } - return resource_id; + return 0; } // static int PageInfoUI::GetConnectionIconID(PageInfo::SiteConnectionStatus status) { - if (base::FeatureList::IsEnabled(page_info::kPageInfoV2)) { - switch (status) { - case PageInfo::SITE_CONNECTION_STATUS_UNKNOWN: - case PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE: - case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED: - return IDR_PAGEINFO_GOOD_V2; - case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE: - case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION: - case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS: - case PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED: - case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE: - case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR: - return IDR_PAGEINFO_BAD_V2; - } - - return 0; - } - int resource_id = IDR_PAGEINFO_INFO; - switch (status) { case PageInfo::SITE_CONNECTION_STATUS_UNKNOWN: case PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE: - break; case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED: - resource_id = IDR_PAGEINFO_GOOD; - break; + return IDR_PAGEINFO_GOOD; case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE: case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION: case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS: - resource_id = IDR_PAGEINFO_WARNING_MINOR; - break; case PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED: - resource_id = IDR_PAGEINFO_WARNING_MAJOR; - break; case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE: case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR: - resource_id = IDR_PAGEINFO_BAD; - break; + return IDR_PAGEINFO_BAD; } - return resource_id; + return 0; } int PageInfoUI::GetIdentityIconColorID(PageInfo::SiteIdentityStatus status) {
diff --git a/components/password_manager/core/browser/android_affiliation/android_affiliation_service.h b/components/password_manager/core/browser/android_affiliation/android_affiliation_service.h index ce20126..1c28ef3 100644 --- a/components/password_manager/core/browser/android_affiliation/android_affiliation_service.h +++ b/components/password_manager/core/browser/android_affiliation/android_affiliation_service.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_ANDROID_AFFILIATION_SERVICE_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_ANDROID_AFFILIATION_SERVICE_H_ -#include <string> - #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h"
diff --git a/components/password_manager/core/browser/credential_cache.h b/components/password_manager/core/browser/credential_cache.h index cbb13ad..832d7c85 100644 --- a/components/password_manager/core/browser/credential_cache.h +++ b/components/password_manager/core/browser/credential_cache.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_CACHE_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_CACHE_H_ -#include <string> #include <vector> #include "base/types/strong_alias.h"
diff --git a/components/password_manager/core/browser/http_auth_manager_impl.h b/components/password_manager/core/browser/http_auth_manager_impl.h index be88d5e..1bbb4ad 100644 --- a/components/password_manager/core/browser/http_auth_manager_impl.h +++ b/components/password_manager/core/browser/http_auth_manager_impl.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <vector> #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
diff --git a/components/password_manager/core/browser/import/password_importer.h b/components/password_manager/core/browser/import/password_importer.h index 1517bef..a412ea8 100644 --- a/components/password_manager/core/browser/import/password_importer.h +++ b/components/password_manager/core/browser/import/password_importer.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_PASSWORD_IMPORTER_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_PASSWORD_IMPORTER_H_ -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl.h b/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl.h index f1f69a0..65358611 100644 --- a/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl.h +++ b/components/password_manager/core/browser/leak_detection/leak_detection_check_factory_impl.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_CHECK_FACTORY_IMPL_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_CHECK_FACTORY_IMPL_H_ -#include <string> - #include "base/macros.h" #include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h" #include "url/gurl.h"
diff --git a/components/password_manager/core/browser/password_form_filling.h b/components/password_manager/core/browser/password_form_filling.h index 52d143d..2cb828c4 100644 --- a/components/password_manager/core/browser/password_form_filling.h +++ b/components/password_manager/core/browser/password_form_filling.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FILLING_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FILLING_H_ -#include <string> #include <vector> #include "base/memory/weak_ptr.h"
diff --git a/components/password_manager/core/browser/password_reuse_detector_consumer.h b/components/password_manager/core/browser/password_reuse_detector_consumer.h index f7a499a3..76b4dc50 100644 --- a/components/password_manager/core/browser/password_reuse_detector_consumer.h +++ b/components/password_manager/core/browser/password_reuse_detector_consumer.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DETECTOR_CONSUMER_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DETECTOR_CONSUMER_H_ -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/payments/core/payment_address.h b/components/payments/core/payment_address.h index b29b7d4..26e39ec 100644 --- a/components/payments/core/payment_address.h +++ b/components/payments/core/payment_address.h
@@ -6,7 +6,6 @@ #define COMPONENTS_PAYMENTS_CORE_PAYMENT_ADDRESS_H_ #include <memory> -#include <string> #include <vector> #include "components/payments/mojom/payment_request_data.mojom.h"
diff --git a/components/payments/core/payment_currency_amount.h b/components/payments/core/payment_currency_amount.h index 48919c2f..5f72d656 100644 --- a/components/payments/core/payment_currency_amount.h +++ b/components/payments/core/payment_currency_amount.h
@@ -6,7 +6,6 @@ #define COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_ #include <memory> -#include <string> #include "components/payments/mojom/payment_request_data.mojom.h"
diff --git a/components/payments/core/payment_details_modifier.h b/components/payments/core/payment_details_modifier.h index d749236e..8e8132da 100644 --- a/components/payments/core/payment_details_modifier.h +++ b/components/payments/core/payment_details_modifier.h
@@ -6,7 +6,6 @@ #define COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_ #include <memory> -#include <string> #include <vector> #include "components/payments/core/payment_item.h"
diff --git a/components/pdf/renderer/BUILD.gn b/components/pdf/renderer/BUILD.gn index 49fa2d3..48d09ca 100644 --- a/components/pdf/renderer/BUILD.gn +++ b/components/pdf/renderer/BUILD.gn
@@ -3,6 +3,9 @@ # found in the LICENSE file. import("//build/config/features.gni") +import("//pdf/features.gni") + +assert(enable_pdf) static_library("renderer") { sources = [
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h index a7cca7d..710f243 100644 --- a/components/pdf/renderer/pdf_accessibility_tree.h +++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <vector> #include "content/public/renderer/plugin_ax_tree_source.h"
diff --git a/components/performance_manager/performance_manager_registry_impl.h b/components/performance_manager/performance_manager_registry_impl.h index 290d19d7..309c702f 100644 --- a/components/performance_manager/performance_manager_registry_impl.h +++ b/components/performance_manager/performance_manager_registry_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_PERFORMANCE_MANAGER_PERFORMANCE_MANAGER_REGISTRY_IMPL_H_ #include <memory> -#include <string> #include "base/containers/flat_map.h" #include "base/containers/flat_set.h"
diff --git a/components/performance_manager/performance_manager_tab_helper.h b/components/performance_manager/performance_manager_tab_helper.h index 8ffb2c7e..6ded9df 100644 --- a/components/performance_manager/performance_manager_tab_helper.h +++ b/components/performance_manager/performance_manager_tab_helper.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/performance_manager/persistence/site_data/site_data_cache_inspector.h b/components/performance_manager/persistence/site_data/site_data_cache_inspector.h index 70f9f40..c4294a6 100644 --- a/components/performance_manager/persistence/site_data/site_data_cache_inspector.h +++ b/components/performance_manager/persistence/site_data/site_data_cache_inspector.h
@@ -7,7 +7,6 @@ #include <cstdint> #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc b/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc index 526540f..abe7b8fd 100644 --- a/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc +++ b/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
@@ -23,6 +23,7 @@ #include "base/test/test_timeouts.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "build/build_config.h" #include "components/performance_manager/graph/frame_node_impl.h" #include "components/performance_manager/graph/page_node_impl.h" #include "components/performance_manager/graph/process_node_impl.h" @@ -1345,7 +1346,13 @@ memory_request.RemoveObserver(&observer); } -TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) { +// TODO(crbug.com/1203439) Sometimes timing out on Windows. +#if defined(OS_WIN) +#define MAYBE_SingleProcessRequest DISABLED_SingleProcessRequest +#else +#define MAYBE_SingleProcessRequest SingleProcessRequest +#endif +TEST_F(V8DetailedMemoryDecoratorTest, MAYBE_SingleProcessRequest) { // Create 2 renderer processes. Create one request that measures both of // them, and one request that measures only one. constexpr RenderProcessHostId kProcessId1 = RenderProcessHostId(0xFAB);
diff --git a/components/permissions/permission_prompt.h b/components/permissions/permission_prompt.h index a1e3dec7..d671876 100644 --- a/components/permissions/permission_prompt.h +++ b/components/permissions/permission_prompt.h
@@ -6,7 +6,6 @@ #define COMPONENTS_PERMISSIONS_PERMISSION_PROMPT_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/policy/core/browser/url_blocklist_manager.h b/components/policy/core/browser/url_blocklist_manager.h index d1713d7c..f87e4fe 100644 --- a/components/policy/core/browser/url_blocklist_manager.h +++ b/components/policy/core/browser/url_blocklist_manager.h
@@ -10,7 +10,6 @@ #include <map> #include <memory> -#include <string> #include "base/compiler_specific.h" #include "base/macros.h"
diff --git a/components/policy/core/common/policy_bundle.h b/components/policy/core/common/policy_bundle.h index 955e34df..03bb4f8 100644 --- a/components/policy/core/common/policy_bundle.h +++ b/components/policy/core/common/policy_bundle.h
@@ -6,7 +6,6 @@ #define COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_ #include <map> -#include <string> #include "base/macros.h" #include "components/policy/core/common/policy_map.h"
diff --git a/components/policy/core/common/policy_service_impl.h b/components/policy/core/common/policy_service_impl.h index f9dec79..286a304 100644 --- a/components/policy/core/common/policy_service_impl.h +++ b/components/policy/core/common/policy_service_impl.h
@@ -8,7 +8,6 @@ #include <map> #include <memory> #include <set> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/query_tiles/test/test_utils.h b/components/query_tiles/test/test_utils.h index eae4b61..69766de2 100644 --- a/components/query_tiles/test/test_utils.h +++ b/components/query_tiles/test/test_utils.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_QUERY_TILES_TEST_TEST_UTILS_H_ #define COMPONENTS_QUERY_TILES_TEST_TEST_UTILS_H_ -#include <string> #include <vector> #include "components/query_tiles/internal/tile_group.h"
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm index 73e4509..e301610a 100644 --- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm +++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
@@ -354,11 +354,7 @@ return; if (![self _isConsideredOpenForPersistentState]) return; - // By the time state is restored, we don't want to miniaturize. Windows will - // be properly restored as miniaturized despite us not saving this. - // See https://crbug.com/1204517 for context/details. - if ([self isMiniaturized]) - return; + base::scoped_nsobject<NSMutableData> restorableStateData( [[NSMutableData alloc] init]); base::scoped_nsobject<NSKeyedArchiver> encoder([[NSKeyedArchiver alloc]
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h index 253e773c..b4655c1c 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -293,6 +293,9 @@ // Returns true if capture exists and is currently active. bool HasCapture(); + // Returns true if window restoration data exists from session restore. + bool HasWindowRestorationData(); + // CocoaMouseCaptureDelegate: void PostCapturedEvent(NSEvent* event) override; void OnMouseCaptureLost() override; @@ -383,7 +386,7 @@ bool invalidate_shadow_on_frame_swap_ = false; // A blob representing the window's saved state, which is applied and cleared - // the first time it's shown. + // on the first call to SetVisibilityState(). std::vector<uint8_t> pending_restoration_data_; mojo::AssociatedReceiver<remote_cocoa::mojom::NativeWidgetNSWindow>
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm index f20d8147..def66d5 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -654,6 +654,33 @@ void NativeWidgetNSWindowBridge::SetVisibilityState( WindowVisibilityState new_state) { + // During session restore this method gets called from RestoreTabsToBrowser() + // with new_state = kShowAndActivateWindow. We consume restoration data on our + // first time through this method so we can use its existence as an + // indication that session restoration is underway. We'll use this later to + // decide whether or not to actually honor the WindowVisibilityState change + // request. This window may live in the dock, for example, in which case we + // don't really want to kShowAndActivateWindow. Even if the window is on the + // desktop we still won't want to kShowAndActivateWindow because doing so + // might trigger a transition to a different space (and we don't want to + // switch spaces on start-up). When session restore determines the Active + // window it will also call SetVisibilityState(), on that pass the window + // can/will be activated. + bool session_restore_in_progress = false; + + // Restore Cocoa window state. + if (HasWindowRestorationData()) { + NSData* restore_ns_data = + [NSData dataWithBytes:pending_restoration_data_.data() + length:pending_restoration_data_.size()]; + base::scoped_nsobject<NSKeyedUnarchiver> decoder( + [[NSKeyedUnarchiver alloc] initForReadingWithData:restore_ns_data]); + [window_ restoreStateWithCoder:decoder]; + pending_restoration_data_.clear(); + + session_restore_in_progress = true; + } + // Ensure that: // - A window with an invisible parent is not made visible. // - A parent changing visibility updates child window visibility. @@ -695,20 +722,11 @@ return; } - if (!pending_restoration_data_.empty()) { - NSData* restore_ns_data = - [NSData dataWithBytes:pending_restoration_data_.data() - length:pending_restoration_data_.size()]; - base::scoped_nsobject<NSKeyedUnarchiver> decoder( - [[NSKeyedUnarchiver alloc] initForReadingWithData:restore_ns_data]); - [window_ restoreStateWithCoder:decoder]; - pending_restoration_data_.clear(); - - // When first showing a window with restoration data, don't activate it. - // This avoids switching spaces or un-miniaturizing it right away. - // Additional activations act normally. - if (new_state == WindowVisibilityState::kShowAndActivateWindow) - new_state = WindowVisibilityState::kShowInactive; + // Don't activate a window during session restore, to avoid switching spaces + // (or pulling it out of the dock) during startup. + if (session_restore_in_progress && + new_state == WindowVisibilityState::kShowAndActivateWindow) { + new_state = WindowVisibilityState::kShowInactive; } if (IsWindowModalSheet()) { @@ -780,6 +798,10 @@ return mouse_capture_ && mouse_capture_->IsActive(); } +bool NativeWidgetNSWindowBridge::HasWindowRestorationData() { + return !pending_restoration_data_.empty(); +} + bool NativeWidgetNSWindowBridge::RunMoveLoop(const gfx::Vector2d& drag_offset) { // https://crbug.com/876493 CHECK(!HasCapture());
diff --git a/components/reporting/client/report_queue_provider.h b/components/reporting/client/report_queue_provider.h index 11e9332..5d961f6 100644 --- a/components/reporting/client/report_queue_provider.h +++ b/components/reporting/client/report_queue_provider.h
@@ -6,7 +6,6 @@ #define COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_PROVIDER_H_ #include <memory> -#include <string> #include <utility> #include "base/callback.h"
diff --git a/components/reporting/storage/storage.h b/components/reporting/storage/storage.h index 1be689f..6578d5d7 100644 --- a/components/reporting/storage/storage.h +++ b/components/reporting/storage/storage.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <utility> #include "base/callback.h"
diff --git a/components/reporting/util/statusor.h b/components/reporting/util/statusor.h index 89fdfbd..f287281f 100644 --- a/components/reporting/util/statusor.h +++ b/components/reporting/util/statusor.h
@@ -57,7 +57,6 @@ #define COMPONENTS_REPORTING_UTIL_STATUSOR_H_ #include <new> -#include <string> #include <type_traits> #include <utility>
diff --git a/components/reputation/core/safety_tip_test_utils.cc b/components/reputation/core/safety_tip_test_utils.cc index 165e09c..1b45d901 100644 --- a/components/reputation/core/safety_tip_test_utils.cc +++ b/components/reputation/core/safety_tip_test_utils.cc
@@ -53,13 +53,16 @@ } void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns, - std::vector<std::string> target_patterns) { + std::vector<std::string> target_patterns, + std::vector<std::string> common_words) { auto config_proto = GetConfig(); config_proto->clear_allowed_pattern(); config_proto->clear_allowed_target_pattern(); + config_proto->clear_common_word(); std::sort(patterns.begin(), patterns.end()); std::sort(target_patterns.begin(), target_patterns.end()); + std::sort(common_words.begin(), common_words.end()); for (const auto& pattern : patterns) { UrlPattern* page = config_proto->add_allowed_pattern(); @@ -69,11 +72,14 @@ HostPattern* page = config_proto->add_allowed_target_pattern(); page->set_regex(pattern); } + for (const auto& word : common_words) { + config_proto->add_common_word(word); + } SetSafetyTipsRemoteConfigProto(std::move(config_proto)); } void InitializeBlankLookalikeAllowlistForTesting() { - SetSafetyTipAllowlistPatterns({}, {}); + SetSafetyTipAllowlistPatterns({}, {}, {}); } } // namespace reputation
diff --git a/components/reputation/core/safety_tip_test_utils.h b/components/reputation/core/safety_tip_test_utils.h index 666f97f..58b8065 100644 --- a/components/reputation/core/safety_tip_test_utils.h +++ b/components/reputation/core/safety_tip_test_utils.h
@@ -31,7 +31,8 @@ // |target_patterns| is the list of hostname regexes allowed to be targets of // lookalikes. void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns, - std::vector<std::string> target_patterns); + std::vector<std::string> target_patterns, + std::vector<std::string> common_words); // Ensure that the allowlist has been initialized. This is important as some // code (e.g. the elision policy) is fail-open (i.e. it won't elide without an
diff --git a/components/reputation/core/safety_tips.proto b/components/reputation/core/safety_tips.proto index b14bfaa3..44b5b520 100644 --- a/components/reputation/core/safety_tips.proto +++ b/components/reputation/core/safety_tips.proto
@@ -65,4 +65,9 @@ // In these cases it's simpler to allowlist the target instead of the // embedder. repeated HostPattern allowed_target_pattern = 4; + + // A *sorted* list of common words. These words are combined with the list at + // components/url_formatter/spoof_checks/common_words. The combined list is + // used in some lookalike heuristics to prevent common false positives. + repeated string common_word = 5; }
diff --git a/components/reputation/core/safety_tips_config.cc b/components/reputation/core/safety_tips_config.cc index e3cf98d..a3ef886 100644 --- a/components/reputation/core/safety_tips_config.cc +++ b/components/reputation/core/safety_tips_config.cc
@@ -5,6 +5,7 @@ #include "components/reputation/core/safety_tips_config.h" #include "base/no_destructor.h" +#include "base/ranges/algorithm.h" #include "components/safe_browsing/core/db/v4_protocol_manager_util.h" #include "third_party/re2/src/re2/re2.h" #include "url/gurl.h" @@ -169,4 +170,20 @@ return security_state::SafetyTipStatus::kNone; } +bool IsCommonWordInConfigProto(const SafetyTipsConfig* proto, + const std::string& word) { + // proto is nullptr when running in non-Lookalike tests. + if (proto == nullptr) { + return false; + } + + auto common_words = proto->common_word(); + DCHECK(base::ranges::is_sorted(common_words.begin(), common_words.end())); + auto lower = std::lower_bound( + common_words.begin(), common_words.end(), word, + [](const std::string& a, const std::string& b) -> bool { return a < b; }); + + return lower != common_words.end() && word == *lower; +} + } // namespace reputation
diff --git a/components/reputation/core/safety_tips_config.h b/components/reputation/core/safety_tips_config.h index 532c0dc..9d0d406 100644 --- a/components/reputation/core/safety_tips_config.h +++ b/components/reputation/core/safety_tips_config.h
@@ -42,6 +42,10 @@ // in sorted order. security_state::SafetyTipStatus GetSafetyTipUrlBlockType(const GURL& url); +// Returns whether |word| is included in the component updater common word list +bool IsCommonWordInConfigProto(const SafetyTipsConfig* proto, + const std::string& word); + } // namespace reputation #endif // COMPONENTS_REPUTATION_CORE_SAFETY_TIPS_CONFIG_H_
diff --git a/components/reputation/core/safety_tips_config_unittest.cc b/components/reputation/core/safety_tips_config_unittest.cc index 792f54c..4c7756e 100644 --- a/components/reputation/core/safety_tips_config_unittest.cc +++ b/components/reputation/core/safety_tips_config_unittest.cc
@@ -13,7 +13,7 @@ namespace reputation { TEST(SafetyTipsConfigTest, TestUrlAllowlist) { - SetSafetyTipAllowlistPatterns({"example.com/"}, {}); + SetSafetyTipAllowlistPatterns({"example.com/"}, {}, {}); auto* config = GetSafetyTipsRemoteConfigProto(); EXPECT_TRUE(IsUrlAllowlistedBySafetyTipsComponent( config, GURL("http://example.com"))); @@ -22,7 +22,7 @@ } TEST(SafetyTipsConfigTest, TestTargetUrlAllowlist) { - SetSafetyTipAllowlistPatterns({}, {"exa.*\\.com"}); + SetSafetyTipAllowlistPatterns({}, {"exa.*\\.com"}, {}); auto* config = GetSafetyTipsRemoteConfigProto(); EXPECT_TRUE( IsTargetHostAllowlistedBySafetyTipsComponent(config, "example.com")); @@ -30,4 +30,14 @@ IsTargetHostAllowlistedBySafetyTipsComponent(config, "example.org")); } +TEST(SafetyTipsConfigTest, TestCommonWords) { + // IsCommonWordInConfigProto does a binary search of sorted common words. + SetSafetyTipAllowlistPatterns({}, {}, {"common3", "common1", "common2"}); + auto* config = GetSafetyTipsRemoteConfigProto(); + EXPECT_TRUE(IsCommonWordInConfigProto(config, "common1")); + EXPECT_TRUE(IsCommonWordInConfigProto(config, "common2")); + EXPECT_TRUE(IsCommonWordInConfigProto(config, "common3")); + EXPECT_FALSE(IsCommonWordInConfigProto(config, "uncommon")); +} + } // namespace reputation
diff --git a/components/resources/android/page_info_resource_id.h b/components/resources/android/page_info_resource_id.h index dd09006..7ec3a91 100644 --- a/components/resources/android/page_info_resource_id.h +++ b/components/resources/android/page_info_resource_id.h
@@ -24,23 +24,9 @@ // PageInfoUI images, used in ConnectionInfoView // Good: -DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD, R.drawable.pageinfo_good) -DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD_V2, R.drawable.omnibox_https_valid) -// Warnings: -DECLARE_RESOURCE_ID(IDR_PAGEINFO_WARNING_MINOR, R.drawable.pageinfo_warning) +DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD, R.drawable.omnibox_https_valid) // Bad: -DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD, R.drawable.pageinfo_bad) -DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD_V2, R.drawable.omnibox_not_secure_warning) -// Should never occur, use warning just in case: -// Enterprise managed: ChromeOS only. -DECLARE_RESOURCE_ID(IDR_PAGEINFO_ENTERPRISE_MANAGED, - R.drawable.pageinfo_warning) -// Info: Only shown on chrome:// urls, which don't show the connection info -// popup. -DECLARE_RESOURCE_ID(IDR_PAGEINFO_INFO, R.drawable.pageinfo_warning) -// Major warning: Used on insecure pages, which don't show the connection info -// popup. -DECLARE_RESOURCE_ID(IDR_PAGEINFO_WARNING_MAJOR, R.drawable.pageinfo_warning) +DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD, R.drawable.omnibox_not_secure_warning) // PageInfoUI colors, used in ConnectionInfoView // Good:
diff --git a/components/safe_browsing/android/safe_browsing_api_handler.h b/components/safe_browsing/android/safe_browsing_api_handler.h index a343c4b..b4be21c 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler.h +++ b/components/safe_browsing/android/safe_browsing_api_handler.h
@@ -9,7 +9,6 @@ #define COMPONENTS_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_bridge.h b/components/safe_browsing/android/safe_browsing_api_handler_bridge.h index bcee335..4ba4ebb8 100644 --- a/components/safe_browsing/android/safe_browsing_api_handler_bridge.h +++ b/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
@@ -9,7 +9,6 @@ #include <jni.h> -#include <string> #include <vector> #include "base/android/jni_android.h"
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model.cc b/components/safe_browsing/content/browser/client_side_phishing_model.cc index b37fb01a..bf77c6d7 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model.cc +++ b/components/safe_browsing/content/browser/client_side_phishing_model.cc
@@ -4,9 +4,11 @@ #include "components/safe_browsing/content/browser/client_side_phishing_model.h" +#include "base/command_line.h" #include "base/memory/singleton.h" #include "base/metrics/histogram_functions.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "components/safe_browsing/core/proto/client_model.pb.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -14,6 +16,29 @@ namespace safe_browsing { +namespace { + +// Command-line flag that can be used to override the current CSD model. Must be +// provided with an absolute path. +const char kOverrideCsdModelFlag[] = "csd-model-override-path"; + +std::string ReadFileIntoString(base::FilePath path) { + if (path.empty()) + return std::string(); + + base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!file.IsValid()) + return std::string(); + + std::vector<char> model_data(file.GetLength()); + if (file.ReadAtCurrentPos(model_data.data(), model_data.size()) == -1) + return std::string(); + + return std::string(model_data.begin(), model_data.end()); +} + +} // namespace + using base::AutoLock; struct ClientSidePhishingModelSingletonTrait @@ -32,7 +57,9 @@ ClientSidePhishingModelSingletonTrait>::get(); } -ClientSidePhishingModel::ClientSidePhishingModel() = default; +ClientSidePhishingModel::ClientSidePhishingModel() { + MaybeOverrideModel(); +} ClientSidePhishingModel::~ClientSidePhishingModel() { AutoLock lock(lock_); // DCHECK fail if the lock is held. @@ -62,7 +89,9 @@ AutoLock lock(lock_); bool proto_valid = false; - if (!model_str.empty()) { + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + kOverrideCsdModelFlag) && + !model_str.empty()) { ClientSideModel model_proto; proto_valid = model_proto.ParseFromString(model_str); base::UmaHistogramBoolean("SBClientPhishing.ModelDynamicUpdateSuccess", @@ -108,4 +137,42 @@ visual_tflite_model_ = std::move(file); } +void ClientSidePhishingModel::MaybeOverrideModel() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + kOverrideCsdModelFlag)) { + base::FilePath overriden_model_path = + base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + kOverrideCsdModelFlag); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ReadFileIntoString, overriden_model_path), + // base::Unretained is safe because this is a singleton. + base::BindOnce(&ClientSidePhishingModel::OnGetOverridenModelData, + base::Unretained(this))); + } +} + +void ClientSidePhishingModel::OnGetOverridenModelData( + const std::string& model_data) { + if (model_data.empty()) { + VLOG(2) << "Overriden model data is empty"; + return; + } + + std::unique_ptr<ClientSideModel> model(new ClientSideModel()); + if (!model->ParseFromArray(model_data.data(), model_data.size())) { + VLOG(2) << "Overriden model data is not a valid ClientSideModel proto"; + return; + } + + VLOG(2) << "Model overriden successfully"; + model_str_ = model_data; + + // Unretained is safe because this is a singleton. + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&ClientSidePhishingModel::NotifyCallbacksOnUI, + base::Unretained(this))); +} + } // namespace safe_browsing
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model.h b/components/safe_browsing/content/browser/client_side_phishing_model.h index bd0dde6..021162c 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model.h +++ b/components/safe_browsing/content/browser/client_side_phishing_model.h
@@ -59,6 +59,12 @@ void NotifyCallbacksOnUI(); + // Called to check the command line and maybe override the current model. + void MaybeOverrideModel(); + + // Callback when the local file overriding the model has been read. + void OnGetOverridenModelData(const std::string& model_data); + // The list of callbacks to notify when a new model is ready. Protected by // lock_. Will always be notified on the UI thread. base::RepeatingCallbackList<void()> callbacks_; @@ -72,6 +78,7 @@ mutable base::Lock lock_; friend struct ClientSidePhishingModelSingletonTrait; + FRIEND_TEST_ALL_PREFIXES(ClientSidePhishingModelTest, CanOverrideWithFlag); }; } // namespace safe_browsing
diff --git a/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc b/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc index 7ce5927c2..66d3147 100644 --- a/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc +++ b/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc
@@ -7,6 +7,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/logging.h" #include "base/run_loop.h" +#include "base/test/scoped_command_line.h" #include "components/safe_browsing/core/proto/client_model.pb.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -158,4 +159,42 @@ EXPECT_TRUE(ClientSidePhishingModel::GetInstance()->IsEnabled()); } +TEST(ClientSidePhishingModelTest, CanOverrideWithFlag) { + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath file_path = + temp_dir.GetPath().AppendASCII("overridden_model.proto"); + base::File file(file_path, base::File::FLAG_OPEN_ALWAYS | + base::File::FLAG_READ | + base::File::FLAG_WRITE); + ClientSideModel model_proto; + model_proto.set_version(123); + model_proto.set_max_words_per_term(0); // Required field + std::string file_contents = model_proto.SerializeAsString(); + file.WriteAtCurrentPos(file_contents.data(), file_contents.size()); + + base::test::ScopedCommandLine command_line; + command_line.GetProcessCommandLine()->AppendSwitchPath( + "--csd-model-override-path", file_path); + + content::BrowserTaskEnvironment task_environment; + base::RunLoop run_loop; + bool called = false; + base::CallbackListSubscription subscription = + ClientSidePhishingModel::GetInstance()->RegisterCallback( + base::BindRepeating( + [](base::RepeatingClosure quit_closure, bool* called) { + *called = true; + std::move(quit_closure).Run(); + }, + run_loop.QuitClosure(), &called)); + + ClientSidePhishingModel::GetInstance()->MaybeOverrideModel(); + + run_loop.Run(); + + EXPECT_EQ(ClientSidePhishingModel::GetInstance()->GetModelStr(), + file_contents); +} + } // namespace safe_browsing
diff --git a/components/safe_browsing/content/browser/threat_details_history.h b/components/safe_browsing/content/browser/threat_details_history.h index 4f76efe..15fef3f 100644 --- a/components/safe_browsing/content/browser/threat_details_history.h +++ b/components/safe_browsing/content/browser/threat_details_history.h
@@ -7,7 +7,6 @@ // This class gets redirect chain for urls from the history service. -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/security_interstitials/content/cert_report_helper.h b/components/security_interstitials/content/cert_report_helper.h index 41a72e9..64527b7d 100644 --- a/components/security_interstitials/content/cert_report_helper.h +++ b/components/security_interstitials/content/cert_report_helper.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CERT_REPORT_HELPER_H_ #define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CERT_REPORT_HELPER_H_ -#include <string> - #include "base/macros.h" #include "components/security_interstitials/content/certificate_error_report.h" #include "components/security_interstitials/core/controller_client.h"
diff --git a/components/security_interstitials/content/content_metrics_helper.h b/components/security_interstitials/content/content_metrics_helper.h index e073b96a..e6e2352 100644 --- a/components/security_interstitials/content/content_metrics_helper.h +++ b/components/security_interstitials/content/content_metrics_helper.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CONTENT_METRICS_HELPER_H_ #define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_CONTENT_METRICS_HELPER_H_ -#include <string> - #include "base/macros.h" #include "components/captive_portal/core/buildflags.h" #include "components/security_interstitials/core/metrics_helper.h"
diff --git a/components/send_tab_to_self/send_tab_to_self_sync_service.h b/components/send_tab_to_self/send_tab_to_self_sync_service.h index 2dd9097..7e78060 100644 --- a/components/send_tab_to_self/send_tab_to_self_sync_service.h +++ b/components/send_tab_to_self/send_tab_to_self_sync_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SYNC_SERVICE_H_ #include <memory> -#include <string> #include "base/memory/weak_ptr.h" #include "components/keyed_service/core/keyed_service.h"
diff --git a/components/services/storage/indexed_db/scopes/scope_lock.h b/components/services/storage/indexed_db/scopes/scope_lock.h index 26067646..35cde17 100644 --- a/components/services/storage/indexed_db/scopes/scope_lock.h +++ b/components/services/storage/indexed_db/scopes/scope_lock.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SERVICES_STORAGE_INDEXED_DB_SCOPES_SCOPE_LOCK_H_ #include <iosfwd> -#include <string> #include "base/callback.h" #include "base/callback_helpers.h"
diff --git a/components/services/storage/indexed_db/scopes/scopes_lock_manager.h b/components/services/storage/indexed_db/scopes/scopes_lock_manager.h index 3af61e05..4622866 100644 --- a/components/services/storage/indexed_db/scopes/scopes_lock_manager.h +++ b/components/services/storage/indexed_db/scopes/scopes_lock_manager.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SERVICES_STORAGE_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_ #include <iosfwd> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h index 0052728..fe573eeb 100644 --- a/components/signin/core/browser/account_reconcilor.h +++ b/components/signin/core/browser/account_reconcilor.h
@@ -5,7 +5,6 @@ #define COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_H_ #include <memory> -#include <string> #include <vector> #include "base/compiler_specific.h"
diff --git a/components/signin/core/browser/account_reconcilor_delegate.h b/components/signin/core/browser/account_reconcilor_delegate.h index e6ad19f..7e6e287 100644 --- a/components/signin/core/browser/account_reconcilor_delegate.h +++ b/components/signin/core/browser/account_reconcilor_delegate.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_DELEGATE_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_RECONCILOR_DELEGATE_H_ -#include <string> #include <vector> #include "base/time/time.h"
diff --git a/components/signin/core/browser/dice_account_reconcilor_delegate.h b/components/signin/core/browser/dice_account_reconcilor_delegate.h index 1cb43ab..5563584 100644 --- a/components/signin/core/browser/dice_account_reconcilor_delegate.h +++ b/components/signin/core/browser/dice_account_reconcilor_delegate.h
@@ -5,8 +5,6 @@ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_DICE_ACCOUNT_RECONCILOR_DELEGATE_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_DICE_ACCOUNT_RECONCILOR_DELEGATE_H_ -#include <string> - #include "base/macros.h" #include "components/signin/core/browser/account_reconcilor_delegate.h" #include "components/signin/public/base/account_consistency_method.h"
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/components/signin/core/browser/mirror_account_reconcilor_delegate.h index 192325ee..08ff4ec 100644 --- a/components/signin/core/browser/mirror_account_reconcilor_delegate.h +++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_ACCOUNT_RECONCILOR_DELEGATE_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_ACCOUNT_RECONCILOR_DELEGATE_H_ -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/signin/internal/identity_manager/child_account_info_fetcher_android.h b/components/signin/internal/identity_manager/child_account_info_fetcher_android.h index e51b133..864e7347 100644 --- a/components/signin/internal/identity_manager/child_account_info_fetcher_android.h +++ b/components/signin/internal/identity_manager/child_account_info_fetcher_android.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_CHILD_ACCOUNT_INFO_FETCHER_ANDROID_H_ #include <jni.h> -#include <string> #include "base/android/scoped_java_ref.h" #include "components/signin/public/identity_manager/account_info.h"
diff --git a/components/signin/internal/identity_manager/primary_account_manager.h b/components/signin/internal/identity_manager/primary_account_manager.h index d310d5e..a87da77 100644 --- a/components/signin/internal/identity_manager/primary_account_manager.h +++ b/components/signin/internal/identity_manager/primary_account_manager.h
@@ -19,7 +19,6 @@ #define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_PRIMARY_ACCOUNT_MANAGER_H_ #include <memory> -#include <string> #include "base/macros.h" #include "base/observer_list.h"
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h index 263e3de0..7220a445 100644 --- a/components/signin/ios/browser/account_consistency_service.h +++ b/components/signin/ios/browser/account_consistency_service.h
@@ -7,7 +7,6 @@ #include <map> #include <set> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/signin/public/base/multilogin_parameters.h b/components/signin/public/base/multilogin_parameters.h index ee90a46b..4859c7c 100644 --- a/components/signin/public/base/multilogin_parameters.h +++ b/components/signin/public/base/multilogin_parameters.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_SIGNIN_PUBLIC_BASE_MULTILOGIN_PARAMETERS_H_ #define COMPONENTS_SIGNIN_PUBLIC_BASE_MULTILOGIN_PARAMETERS_H_ -#include <string> #include <vector> #include "google_apis/gaia/core_account_id.h"
diff --git a/components/site_isolation/BUILD.gn b/components/site_isolation/BUILD.gn index ee7127a3..464d684 100644 --- a/components/site_isolation/BUILD.gn +++ b/components/site_isolation/BUILD.gn
@@ -49,6 +49,7 @@ deps = [ ":buildflags", "//base", + "//base/util/values:values_util", "//components/prefs", "//components/user_prefs", "//content/public/browser",
diff --git a/components/site_isolation/pref_names.cc b/components/site_isolation/pref_names.cc index 403cf01..4bd35dd 100644 --- a/components/site_isolation/pref_names.cc +++ b/components/site_isolation/pref_names.cc
@@ -8,10 +8,20 @@ namespace prefs { // A list of origins that were heuristically determined to need process -// isolation. For example, an origin may be placed on this list in response to -// the user typing a password on it. +// isolation due to an action triggered by the user. For example, an origin may +// be placed on this list in response to the user typing a password on it. const char kUserTriggeredIsolatedOrigins[] = "site_isolation.user_triggered_isolated_origins"; +// A list of origins that were determined to need process isolation based on +// heuristics triggered directly by web sites. For example, an origin may be +// placed on this list in response to serving Cross-Origin-Opener-Policy +// headers. Unlike the user-triggered list above, web-triggered isolated +// origins are subject to stricter size and eviction policies, to guard against +// too many sites triggering isolation and to eventually stop isolation if web +// sites stop serving headers that triggered it. +const char kWebTriggeredIsolatedOrigins[] = + "site_isolation.web_triggered_isolated_origins"; + } // namespace prefs } // namespace site_isolation
diff --git a/components/site_isolation/pref_names.h b/components/site_isolation/pref_names.h index ca61fa2..c390945 100644 --- a/components/site_isolation/pref_names.h +++ b/components/site_isolation/pref_names.h
@@ -9,6 +9,7 @@ namespace prefs { extern const char kUserTriggeredIsolatedOrigins[]; +extern const char kWebTriggeredIsolatedOrigins[]; } // namespace prefs } // namespace site_isolation
diff --git a/components/site_isolation/site_isolation_policy.cc b/components/site_isolation/site_isolation_policy.cc index f36a3478..615c7aa 100644 --- a/components/site_isolation/site_isolation_policy.cc +++ b/components/site_isolation/site_isolation_policy.cc
@@ -5,8 +5,9 @@ #include "components/site_isolation/site_isolation_policy.h" #include "base/metrics/field_trial_params.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/system/sys_info.h" +#include "base/util/values/values_util.h" #include "build/build_config.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" @@ -16,9 +17,17 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/site_isolation_policy.h" +#include "content/public/common/content_features.h" namespace site_isolation { +namespace { + +using IsolatedOriginSource = + content::ChildProcessSecurityPolicy::IsolatedOriginSource; + +} // namespace + // static bool SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() { // If the user has explicitly enabled site isolation for password sites from @@ -133,12 +142,30 @@ void SiteIsolationPolicy::PersistIsolatedOrigin( content::BrowserContext* context, const url::Origin& origin, - content::ChildProcessSecurityPolicy::IsolatedOriginSource source) { + IsolatedOriginSource source) { + DCHECK(context); DCHECK(!context->IsOffTheRecord()); - // TODO(alexmos): Support web-triggered IsolatedOriginSources. - DCHECK_EQ(source, content::ChildProcessSecurityPolicy::IsolatedOriginSource:: - USER_TRIGGERED); + DCHECK(!origin.opaque()); + // This function currently supports two sources for persistence, for + // user-triggered and web-triggered isolated origins. + if (source == IsolatedOriginSource::USER_TRIGGERED) { + PersistUserTriggeredIsolatedOrigin(context, origin); + } else if (source == IsolatedOriginSource::WEB_TRIGGERED) { + PersistWebTriggeredIsolatedOrigin(context, origin); + } else { + NOTREACHED(); + } +} + +// static +void SiteIsolationPolicy::PersistUserTriggeredIsolatedOrigin( + content::BrowserContext* context, + const url::Origin& origin) { + // User-triggered isolated origins are currently stored in a simple list of + // unlimited size. + // TODO(alexmos): Cap the maximum number of entries and evict older entries. + // See https://crbug.com/1172407. ListPrefUpdate update(user_prefs::UserPrefs::Get(context), site_isolation::prefs::kUserTriggeredIsolatedOrigins); base::ListValue* list = update.Get(); @@ -148,31 +175,91 @@ } // static +void SiteIsolationPolicy::PersistWebTriggeredIsolatedOrigin( + content::BrowserContext* context, + const url::Origin& origin) { + // Web-triggered isolated origins are stored in a dictionary of (origin, + // timestamp) pairs. The number of entries is capped by a field trial param, + // and older entries are evicted. + DictionaryPrefUpdate update( + user_prefs::UserPrefs::Get(context), + site_isolation::prefs::kWebTriggeredIsolatedOrigins); + base::DictionaryValue* dict = update.Get(); + + // Add the origin. If it already exists, this will just update the + // timestamp. + dict->SetKey(origin.Serialize(), util::TimeToValue(base::Time::Now())); + + // Check whether the maximum number of stored sites was exceeded and remove + // one or more entries, starting with the oldest timestamp. Note that more + // than one entry may need to be removed, since the maximum number of entries + // could change over time (via a change in the field trial param). + size_t max_size = + ::features::kSiteIsolationForCrossOriginOpenerPolicyMaxSitesParam.Get(); + while (dict->DictSize() > max_size) { + auto items = dict->DictItems(); + auto oldest_site_time_pair = std::min_element( + items.begin(), items.end(), [](auto pair_a, auto pair_b) { + absl::optional<base::Time> time_a = util::ValueToTime(pair_a.second); + absl::optional<base::Time> time_b = util::ValueToTime(pair_b.second); + // has_value() should always be true unless the prefs were corrupted. + // In that case, prioritize the corrupted entry for removal. + return (time_a.has_value() ? time_a.value() : base::Time::Min()) < + (time_b.has_value() ? time_b.value() : base::Time::Min()); + }); + dict->RemoveKey(oldest_site_time_pair->first); + } +} + +// static void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins( content::BrowserContext* browser_context) { + auto* policy = content::ChildProcessSecurityPolicy::GetInstance(); + // If the user turned off password-triggered isolation, don't apply any // stored isolated origins, but also don't clear them from prefs, so that // they can be used if password-triggered isolation is re-enabled later. - if (!IsIsolationForPasswordSitesEnabled()) - return; + if (IsIsolationForPasswordSitesEnabled()) { + std::vector<url::Origin> origins; + for (const auto& value : user_prefs::UserPrefs::Get(browser_context) + ->GetList(prefs::kUserTriggeredIsolatedOrigins) + ->GetList()) { + origins.push_back(url::Origin::Create(GURL(value.GetString()))); + } - std::vector<url::Origin> origins; - for (const auto& value : user_prefs::UserPrefs::Get(browser_context) - ->GetList(prefs::kUserTriggeredIsolatedOrigins) - ->GetList()) { - origins.push_back(url::Origin::Create(GURL(value.GetString()))); + if (!origins.empty()) { + policy->AddFutureIsolatedOrigins( + origins, IsolatedOriginSource::USER_TRIGGERED, browser_context); + } + + base::UmaHistogramCounts1000( + "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", origins.size()); } - if (!origins.empty()) { - auto* policy = content::ChildProcessSecurityPolicy::GetInstance(); - using IsolatedOriginSource = - content::ChildProcessSecurityPolicy::IsolatedOriginSource; - policy->AddFutureIsolatedOrigins( - origins, IsolatedOriginSource::USER_TRIGGERED, browser_context); - } + // Similarly, load saved web-triggered isolated origins only if isolation of + // COOP sites (currently the only source of these origins) is enabled with + // persistence, but don't remove them from prefs otherwise. + if (content::SiteIsolationPolicy::ShouldPersistIsolatedCOOPSites()) { + std::vector<url::Origin> origins; - UMA_HISTOGRAM_COUNTS_1000( - "SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", origins.size()); + // TODO(alexmos): Implement support for skipping and expiring entries that + // are older than a predefined threshold. + + auto* dict = user_prefs::UserPrefs::Get(browser_context) + ->GetDictionary(prefs::kWebTriggeredIsolatedOrigins); + if (dict) { + for (const auto& site_time_pair : dict->DictItems()) + origins.push_back(url::Origin::Create(GURL(site_time_pair.first))); + } + + if (!origins.empty()) { + policy->AddFutureIsolatedOrigins( + origins, IsolatedOriginSource::WEB_TRIGGERED, browser_context); + } + + base::UmaHistogramCounts100( + "SiteIsolation.SavedWebTriggeredIsolatedOrigins.Size", origins.size()); + } } // static
diff --git a/components/site_isolation/site_isolation_policy.h b/components/site_isolation/site_isolation_policy.h index 28621aa..55e1312 100644 --- a/components/site_isolation/site_isolation_policy.h +++ b/components/site_isolation/site_isolation_policy.h
@@ -87,6 +87,14 @@ static bool ShouldPdfCompositorBeEnabledForOopifs(); private: + // Helpers for implementing PersistIsolatedOrigin(). + static void PersistUserTriggeredIsolatedOrigin( + content::BrowserContext* context, + const url::Origin& origin); + static void PersistWebTriggeredIsolatedOrigin( + content::BrowserContext* context, + const url::Origin& origin); + DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy); };
diff --git a/components/site_isolation/site_isolation_policy_unittest.cc b/components/site_isolation/site_isolation_policy_unittest.cc index 99665ff..d1ed1dd 100644 --- a/components/site_isolation/site_isolation_policy_unittest.cc +++ b/components/site_isolation/site_isolation_policy_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_field_trial_list_resetter.h" +#include "base/util/values/values_util.h" #include "build/branding_buildflags.h" #include "build/build_config.h" #include "components/prefs/pref_registry_simple.h" @@ -38,6 +39,9 @@ namespace site_isolation { namespace { +using IsolatedOriginSource = + content::ChildProcessSecurityPolicy::IsolatedOriginSource; + // Some command-line switches override field trials - the tests need to be // skipped in this case. bool ShouldSkipBecauseOfConflictingCommandLineSwitches() { @@ -101,6 +105,8 @@ public: SiteIsolationPolicyTest() { prefs_.registry()->RegisterListPref(prefs::kUserTriggeredIsolatedOrigins); + prefs_.registry()->RegisterDictionaryPref( + prefs::kWebTriggeredIsolatedOrigins); user_prefs::UserPrefs::Set(&browser_context_, &prefs_); } @@ -117,6 +123,110 @@ DISALLOW_COPY_AND_ASSIGN(SiteIsolationPolicyTest); }; +class WebTriggeredIsolatedOriginsPolicyTest : public SiteIsolationPolicyTest { + public: + WebTriggeredIsolatedOriginsPolicyTest() = default; + + void PersistOrigin(const std::string& origin) { + SiteIsolationPolicy::PersistIsolatedOrigin( + browser_context(), url::Origin::Create(GURL(origin)), + IsolatedOriginSource::WEB_TRIGGERED); + } + + std::vector<std::string> GetStoredOrigins() { + std::vector<std::string> origins; + auto* dict = user_prefs::UserPrefs::Get(browser_context()) + ->GetDictionary(prefs::kWebTriggeredIsolatedOrigins); + for (auto pair : dict->DictItems()) + origins.push_back(pair.first); + return origins; + } + + protected: + void SetUp() override { + // Limit the max number of stored sites to 3. + feature_list_.InitAndEnableFeatureWithParameters( + ::features::kSiteIsolationForCrossOriginOpenerPolicy, + {{"stored_sites_max_size", base::NumberToString(3)}, + {"should_persist_across_restarts", "true"}}); + SetEnableStrictSiteIsolation(false); + SiteIsolationPolicyTest::SetUp(); + } + + private: + base::test::ScopedFeatureList feature_list_; + + DISALLOW_COPY_AND_ASSIGN(WebTriggeredIsolatedOriginsPolicyTest); +}; + +// Verify that persisting web-triggered isolated origins properly saves the +// origins to prefs and respects the maximum number of entries (3 in this +// test). +TEST_F(WebTriggeredIsolatedOriginsPolicyTest, PersistIsolatedOrigin) { + PersistOrigin("https://foo1.com"); + PersistOrigin("https://foo2.com"); + PersistOrigin("https://foo3.com"); + + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo1.com", "https://foo2.com", "https://foo3.com")); + + // Adding foo4.com should evict the oldest entry (foo1.com). + PersistOrigin("https://foo4.com"); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo2.com", "https://foo3.com", "https://foo4.com")); + + // Adding foo5.com and foo6.com should evict the next two oldest entries. + PersistOrigin("https://foo5.com"); + PersistOrigin("https://foo6.com"); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo4.com", "https://foo5.com", "https://foo6.com")); + + // Updating the timestamp on foo5.com should keep the current three entries. + PersistOrigin("https://foo5.com"); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo4.com", "https://foo5.com", "https://foo6.com")); + + // Adding two new entries should now evict foo4.com and foo6.com, since + // foo5.com has a more recent timestamp. + PersistOrigin("https://foo7.com"); + PersistOrigin("https://foo8.com"); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo5.com", "https://foo7.com", "https://foo8.com")); +} + +// Verify that when origins stored in prefs contain more than the current +// maximum number of entries, we clean up older entries when adding a new one +// to go back under the size limit. +TEST_F(WebTriggeredIsolatedOriginsPolicyTest, UpdatedMaxSize) { + // Populate the pref manually with more entries than the 3 allowed by the + // field trial param. + DictionaryPrefUpdate update( + user_prefs::UserPrefs::Get(browser_context()), + site_isolation::prefs::kWebTriggeredIsolatedOrigins); + base::DictionaryValue* dict = update.Get(); + dict->SetKey("https://foo1.com", util::TimeToValue(base::Time::Now())); + dict->SetKey("https://foo2.com", util::TimeToValue(base::Time::Now())); + dict->SetKey("https://foo3.com", util::TimeToValue(base::Time::Now())); + dict->SetKey("https://foo4.com", util::TimeToValue(base::Time::Now())); + dict->SetKey("https://foo5.com", util::TimeToValue(base::Time::Now())); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo1.com", "https://foo2.com", "https://foo3.com", + "https://foo4.com", "https://foo5.com")); + + // Now, attempt to save a new origin. This should evict the three oldest + // entries to make room for the new origin. + PersistOrigin("https://foo6.com"); + EXPECT_THAT(GetStoredOrigins(), + testing::UnorderedElementsAre( + "https://foo4.com", "https://foo5.com", "https://foo6.com")); +} + // Helper class that enables site isolation for password sites. class PasswordSiteIsolationPolicyTest : public SiteIsolationPolicyTest { public:
diff --git a/components/soda/BUILD.gn b/components/soda/BUILD.gn index 134f6c3..b4a8af8 100644 --- a/components/soda/BUILD.gn +++ b/components/soda/BUILD.gn
@@ -19,7 +19,16 @@ ] if (is_chromeos_ash) { - deps += [ "//ash/public/cpp" ] + sources += [ + "soda_installer_impl_chromeos.cc", + "soda_installer_impl_chromeos.h", + ] + + deps += [ + "//ash/public/cpp", + "//chromeos/dbus/dlcservice", + "//ui/base", + ] } }
diff --git a/components/soda/DEPS b/components/soda/DEPS index 565b349b..2a23cda 100644 --- a/components/soda/DEPS +++ b/components/soda/DEPS
@@ -1,9 +1,11 @@ include_rules = [ "+ash/public/cpp", + "+chromeos/dbus/dlcservice/dlcservice_client.h", "+components/component_updater/component_updater_paths.h", "+components/crx_file", "+components/live_caption", "+components/prefs", "+components/strings/grit/components_strings.h", "+media/base", + "+ui/base", ]
diff --git a/chrome/browser/ash/accessibility/soda_installer_impl_chromeos.cc b/components/soda/soda_installer_impl_chromeos.cc similarity index 98% rename from chrome/browser/ash/accessibility/soda_installer_impl_chromeos.cc rename to components/soda/soda_installer_impl_chromeos.cc index 713c175..d24c22f 100644 --- a/chrome/browser/ash/accessibility/soda_installer_impl_chromeos.cc +++ b/components/soda/soda_installer_impl_chromeos.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h" +#include "components/soda/soda_installer_impl_chromeos.h" #include "base/bind.h" #include "base/feature_list.h"
diff --git a/chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h b/components/soda/soda_installer_impl_chromeos.h similarity index 93% rename from chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h rename to components/soda/soda_installer_impl_chromeos.h index ccedccd9..cbcb13c 100644 --- a/chrome/browser/ash/accessibility/soda_installer_impl_chromeos.h +++ b/components/soda/soda_installer_impl_chromeos.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ASH_ACCESSIBILITY_SODA_INSTALLER_IMPL_CHROMEOS_H_ -#define CHROME_BROWSER_ASH_ACCESSIBILITY_SODA_INSTALLER_IMPL_CHROMEOS_H_ +#ifndef COMPONENTS_SODA_SODA_INSTALLER_IMPL_CHROMEOS_H_ +#define COMPONENTS_SODA_SODA_INSTALLER_IMPL_CHROMEOS_H_ #include "base/files/file_path.h" #include "chromeos/dbus/dlcservice/dlcservice_client.h" @@ -92,4 +92,4 @@ } // namespace speech -#endif // CHROME_BROWSER_ASH_ACCESSIBILITY_SODA_INSTALLER_IMPL_CHROMEOS_H_ +#endif // COMPONENTS_SODA_SODA_INSTALLER_IMPL_CHROMEOS_H_
diff --git a/components/speech/chunked_byte_buffer.h b/components/speech/chunked_byte_buffer.h index dddc2ee..418ceaa7 100644 --- a/components/speech/chunked_byte_buffer.h +++ b/components/speech/chunked_byte_buffer.h
@@ -9,7 +9,6 @@ #include <stdint.h> #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.h b/components/subresource_filter/content/browser/async_document_subresource_filter.h index 3ad212f1..defd32c 100644 --- a/components/subresource_filter/content/browser/async_document_subresource_filter.h +++ b/components/subresource_filter/content/browser/async_document_subresource_filter.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_ASYNC_DOCUMENT_SUBRESOURCE_FILTER_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/subresource_filter/content/browser/ruleset_service.h b/components/subresource_filter/content/browser/ruleset_service.h index 33a3176..c2bb66fe 100644 --- a/components/subresource_filter/content/browser/ruleset_service.h +++ b/components/subresource_filter/content/browser/ruleset_service.h
@@ -33,7 +33,6 @@ #include <stdint.h> #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/subresource_filter/tools/ruleset_converter/rule_stream.h b/components/subresource_filter/tools/ruleset_converter/rule_stream.h index bab5871..e24fdb0 100644 --- a/components/subresource_filter/tools/ruleset_converter/rule_stream.h +++ b/components/subresource_filter/tools/ruleset_converter/rule_stream.h
@@ -8,7 +8,6 @@ #include <istream> #include <memory> #include <ostream> -#include <string> #include "components/subresource_filter/tools/ruleset_converter/ruleset_format.h" #include "components/url_pattern_index/proto/rules.pb.h"
diff --git a/components/sync/base/enum_set.h b/components/sync/base/enum_set.h index aef2fa01..138e222 100644 --- a/components/sync/base/enum_set.h +++ b/components/sync/base/enum_set.h
@@ -7,7 +7,6 @@ #include <bitset> #include <cstddef> -#include <string> #include <type_traits> #include <utility>
diff --git a/components/sync/driver/data_type_status_table.h b/components/sync/driver/data_type_status_table.h index 424d74b1..42b39f8f 100644 --- a/components/sync/driver/data_type_status_table.h +++ b/components/sync/driver/data_type_status_table.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_DRIVER_DATA_TYPE_STATUS_TABLE_H_ #include <map> -#include <string> #include "components/sync/base/model_type.h" #include "components/sync/model/sync_error.h"
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h index c9d52fb..65e6a47 100644 --- a/components/sync/driver/model_type_controller.h +++ b/components/sync/driver/model_type_controller.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_DRIVER_MODEL_TYPE_CONTROLLER_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/sync/driver/sync_session_durations_metrics_recorder.h b/components/sync/driver/sync_session_durations_metrics_recorder.h index a381fd281..9dfdcf1 100644 --- a/components/sync/driver/sync_session_durations_metrics_recorder.h +++ b/components/sync/driver/sync_session_durations_metrics_recorder.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_DRIVER_SYNC_SESSION_DURATIONS_METRICS_RECORDER_H_ #include <memory> -#include <string> #include <vector> #include "base/scoped_observation.h"
diff --git a/components/sync/engine/cycle/data_type_tracker.h b/components/sync/engine/cycle/data_type_tracker.h index 1d4b503..7213b38 100644 --- a/components/sync/engine/cycle/data_type_tracker.h +++ b/components/sync/engine/cycle/data_type_tracker.h
@@ -8,7 +8,6 @@ #include <stddef.h> #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/sync/engine/cycle/sync_cycle.h b/components/sync/engine/cycle/sync_cycle.h index bd6ff2a8..a222f23 100644 --- a/components/sync/engine/cycle/sync_cycle.h +++ b/components/sync/engine/cycle/sync_cycle.h
@@ -8,7 +8,6 @@ #include <map> #include <memory> #include <set> -#include <string> #include <utility> #include <vector>
diff --git a/components/sync/engine/nigori/keystore_keys_handler.h b/components/sync/engine/nigori/keystore_keys_handler.h index cbb0b2d..3295a274 100644 --- a/components/sync/engine/nigori/keystore_keys_handler.h +++ b/components/sync/engine/nigori/keystore_keys_handler.h
@@ -5,7 +5,6 @@ #ifndef COMPONENTS_SYNC_ENGINE_NIGORI_KEYSTORE_KEYS_HANDLER_H_ #define COMPONENTS_SYNC_ENGINE_NIGORI_KEYSTORE_KEYS_HANDLER_H_ -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/sync/engine/sync_scheduler.h b/components/sync/engine/sync_scheduler.h index fedfa2d..63f2a6a 100644 --- a/components/sync/engine/sync_scheduler.h +++ b/components/sync/engine/sync_scheduler.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_ENGINE_SYNC_SCHEDULER_H_ #include <memory> -#include <string> #include "base/callback.h" #include "base/compiler_specific.h"
diff --git a/components/sync/model/blocking_model_type_store.h b/components/sync/model/blocking_model_type_store.h index 532eb36c..ea54802 100644 --- a/components/sync/model/blocking_model_type_store.h +++ b/components/sync/model/blocking_model_type_store.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_MODEL_BLOCKING_MODEL_TYPE_STORE_H_ #include <memory> -#include <string> #include "components/sync/base/model_type.h" #include "components/sync/model/model_error.h"
diff --git a/components/sync/model/model_type_store.h b/components/sync/model/model_type_store.h index 3078550ca..501fc9f9 100644 --- a/components/sync/model/model_type_store.h +++ b/components/sync/model/model_type_store.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_MODEL_MODEL_TYPE_STORE_H_ #include <memory> -#include <string> #include "base/callback.h" #include "base/macros.h"
diff --git a/components/sync/model/model_type_store_impl.h b/components/sync/model/model_type_store_impl.h index afb1873..c47b6c3 100644 --- a/components/sync/model/model_type_store_impl.h +++ b/components/sync/model/model_type_store_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_MODEL_MODEL_TYPE_STORE_IMPL_H_ #include <memory> -#include <string> #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h"
diff --git a/components/sync/test/fake_server/android/fake_server_helper_android.h b/components/sync/test/fake_server/android/fake_server_helper_android.h index 8ca53165..f5c71d02 100644 --- a/components/sync/test/fake_server/android/fake_server_helper_android.h +++ b/components/sync/test/fake_server/android/fake_server_helper_android.h
@@ -8,7 +8,6 @@ #include <jni.h> #include <memory> -#include <string> #include "base/android/scoped_java_ref.h" #include "components/sync/test/fake_server/entity_builder_factory.h"
diff --git a/components/sync/test/model/fake_model_type_controller_delegate.h b/components/sync/test/model/fake_model_type_controller_delegate.h index d0998639..afb24fe 100644 --- a/components/sync/test/model/fake_model_type_controller_delegate.h +++ b/components/sync/test/model/fake_model_type_controller_delegate.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_TEST_MODEL_FAKE_MODEL_TYPE_CONTROLLER_DELEGATE_H_ #include <memory> -#include <string> #include "base/memory/weak_ptr.h" #include "components/sync/base/model_type.h"
diff --git a/components/sync/trusted_vault/securebox.h b/components/sync/trusted_vault/securebox.h index 5310e7d..fa5486b 100644 --- a/components/sync/trusted_vault/securebox.h +++ b/components/sync/trusted_vault/securebox.h
@@ -7,7 +7,6 @@ #include <cstdint> #include <memory> -#include <string> #include <vector> #include "base/containers/span.h"
diff --git a/components/sync/trusted_vault/trusted_vault_connection.h b/components/sync/trusted_vault/trusted_vault_connection.h index 400bf06f..faff2fba 100644 --- a/components/sync/trusted_vault/trusted_vault_connection.h +++ b/components/sync/trusted_vault/trusted_vault_connection.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_H_ #include <memory> -#include <string> #include <vector> #include "base/callback.h"
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl.h b/components/sync/trusted_vault/trusted_vault_connection_impl.h index 1485df1..626b0352 100644 --- a/components/sync/trusted_vault/trusted_vault_connection_impl.h +++ b/components/sync/trusted_vault/trusted_vault_connection_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_IMPL_H_ #include <memory> -#include <string> #include <vector> #include "base/memory/scoped_refptr.h"
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h index dc32e41..dcf8f89 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler.h +++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_REMOTE_UPDATES_HANDLER_H_ #include <map> -#include <string> #include <vector> #include "components/sync/base/unique_position.h"
diff --git a/components/sync_device_info/device_info_sync_service_impl.h b/components/sync_device_info/device_info_sync_service_impl.h index b2209da..7be70a9c 100644 --- a/components/sync_device_info/device_info_sync_service_impl.h +++ b/components/sync_device_info/device_info_sync_service_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_DEVICE_INFO_DEVICE_INFO_SYNC_SERVICE_IMPL_H_ #include <memory> -#include <string> #include "base/callback_helpers.h" #include "components/sync/invalidations/fcm_registration_token_observer.h"
diff --git a/components/sync_sessions/session_sync_service_impl.h b/components/sync_sessions/session_sync_service_impl.h index 234abb8..08e46e64 100644 --- a/components/sync_sessions/session_sync_service_impl.h +++ b/components/sync_sessions/session_sync_service_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_IMPL_H_ #include <memory> -#include <string> #include "base/callback_list.h" #include "base/memory/weak_ptr.h"
diff --git a/components/sync_sessions/tab_node_pool.h b/components/sync_sessions/tab_node_pool.h index 01f6874..39f1c5b 100644 --- a/components/sync_sessions/tab_node_pool.h +++ b/components/sync_sessions/tab_node_pool.h
@@ -9,7 +9,6 @@ #include <map> #include <set> -#include <string> #include "base/feature_list.h" #include "base/macros.h"
diff --git a/components/sync_user_events/fake_user_event_service.h b/components/sync_user_events/fake_user_event_service.h index 7b3bee3..64ea7c1 100644 --- a/components/sync_user_events/fake_user_event_service.h +++ b/components/sync_user_events/fake_user_event_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_USER_EVENTS_FAKE_USER_EVENT_SERVICE_H_ #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/sync_user_events/no_op_user_event_service.h b/components/sync_user_events/no_op_user_event_service.h index fd69d6f..1f385af 100644 --- a/components/sync_user_events/no_op_user_event_service.h +++ b/components/sync_user_events/no_op_user_event_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_USER_EVENTS_NO_OP_USER_EVENT_SERVICE_H_ #include <memory> -#include <string> #include "base/macros.h" #include "components/sync_user_events/user_event_service.h"
diff --git a/components/sync_user_events/user_event_service.h b/components/sync_user_events/user_event_service.h index 75d6ea43..c8d5b93 100644 --- a/components/sync_user_events/user_event_service.h +++ b/components/sync_user_events/user_event_service.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_USER_EVENTS_USER_EVENT_SERVICE_H_ #include <memory> -#include <string> #include "base/macros.h" #include "base/memory/weak_ptr.h"
diff --git a/components/sync_user_events/user_event_service_impl.h b/components/sync_user_events/user_event_service_impl.h index 70ea7636..968252e 100644 --- a/components/sync_user_events/user_event_service_impl.h +++ b/components/sync_user_events/user_event_service_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_SYNC_USER_EVENTS_USER_EVENT_SERVICE_IMPL_H_ #include <memory> -#include <string> #include "base/macros.h" #include "base/memory/weak_ptr.h"
diff --git a/components/translate/core/browser/mock_translate_ranker.h b/components/translate/core/browser/mock_translate_ranker.h index cc6b513f..c2aa345c 100644 --- a/components/translate/core/browser/mock_translate_ranker.h +++ b/components/translate/core/browser/mock_translate_ranker.h
@@ -6,14 +6,12 @@ #define COMPONENTS_TRANSLATE_CORE_BROWSER_MOCK_TRANSLATE_RANKER_H_ #include <memory> -#include <string> #include <vector> #include "components/translate/core/browser/translate_ranker.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "testing/gmock/include/gmock/gmock.h" - namespace metrics { class TranslateEventProto; }
diff --git a/components/translate/core/browser/translate_ranker.h b/components/translate/core/browser/translate_ranker.h index 243aafe..7f9f836 100644 --- a/components/translate/core/browser/translate_ranker.h +++ b/components/translate/core/browser/translate_ranker.h
@@ -6,7 +6,6 @@ #define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_RANKER_H_ #include <memory> -#include <string> #include <vector> #include "base/macros.h"
diff --git a/components/update_client/background_downloader_win.h b/components/update_client/background_downloader_win.h index db3aa3e..1abccbf 100644 --- a/components/update_client/background_downloader_win.h +++ b/components/update_client/background_downloader_win.h
@@ -10,7 +10,6 @@ #include <wrl/client.h> #include <memory> -#include <string> #include "base/memory/ref_counted.h" #include "base/sequence_checker.h"
diff --git a/components/user_manager/user_image/user_image.h b/components/user_manager/user_image/user_image.h index 55e4978..7b8da59 100644 --- a/components/user_manager/user_image/user_image.h +++ b/components/user_manager/user_image/user_image.h
@@ -6,7 +6,6 @@ #define COMPONENTS_USER_MANAGER_USER_IMAGE_USER_IMAGE_H_ #include <memory> -#include <string> #include <vector> #include "base/files/file_path.h"
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc index b4a90d2c..2b64ee3 100644 --- a/components/variations/variations_ids_provider.cc +++ b/components/variations/variations_ids_provider.cc
@@ -359,10 +359,10 @@ // This is the bottleneck for the creation of the header, so validate the size // here. Force a hard maximum on the ID count in case the Variations server // returns too many IDs and DOSs receiving servers with large requests. - DCHECK_LE(total_id_count, 35U); + DCHECK_LE(total_id_count, 50U); UMA_HISTOGRAM_COUNTS_100("Variations.Headers.ExperimentCount", total_id_count); - if (total_id_count > 50) + if (total_id_count > 75) return std::string(); std::string serialized;
diff --git a/components/variations/variations_murmur_hash.h b/components/variations/variations_murmur_hash.h index a1e28ee3..d4a0291 100644 --- a/components/variations/variations_murmur_hash.h +++ b/components/variations/variations_murmur_hash.h
@@ -6,7 +6,6 @@ #define COMPONENTS_VARIATIONS_VARIATIONS_MURMUR_HASH_H_ #include <cstdint> -#include <string> #include <vector> #include "base/compiler_specific.h"
diff --git a/components/viz/common/frame_sinks/begin_frame_source.h b/components/viz/common/frame_sinks/begin_frame_source.h index c57af2fe..c05efdb 100644 --- a/components/viz/common/frame_sinks/begin_frame_source.h +++ b/components/viz/common/frame_sinks/begin_frame_source.h
@@ -9,7 +9,6 @@ #include <stdint.h> #include <memory> -#include <string> #include "base/check.h" #include "base/containers/flat_set.h"
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h index dfc9bb3..988868e 100644 --- a/components/viz/service/display/surface_aggregator.h +++ b/components/viz/service/display/surface_aggregator.h
@@ -6,7 +6,6 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_SURFACE_AGGREGATOR_H_ #include <memory> -#include <string> #include <unordered_map> #include <utility> #include <vector>
diff --git a/components/viz/service/main/viz_main_impl.h b/components/viz/service/main/viz_main_impl.h index 37c89f0..27e0c52 100644 --- a/components/viz/service/main/viz_main_impl.h +++ b/components/viz/service/main/viz_main_impl.h
@@ -6,7 +6,6 @@ #define COMPONENTS_VIZ_SERVICE_MAIN_VIZ_MAIN_IMPL_H_ #include <memory> -#include <string> #include <vector> #include "base/single_thread_task_runner.h"
diff --git a/components/webapps/browser/installable/installable_manager.h b/components/webapps/browser/installable/installable_manager.h index a7abdf4b8..bb161de 100644 --- a/components/webapps/browser/installable/installable_manager.h +++ b/components/webapps/browser/installable/installable_manager.h
@@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <string> #include <vector> #include "base/callback_forward.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 7f32ce81..b104146 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1023,6 +1023,8 @@ "interest_group/ad_auction.h", "interest_group/ad_auction_service_impl.cc", "interest_group/ad_auction_service_impl.h", + "interest_group/auction_runner.cc", + "interest_group/auction_runner.h", "interest_group/auction_url_loader_factory_proxy.cc", "interest_group/auction_url_loader_factory_proxy.h", "interest_group/interest_group_manager.cc", @@ -2225,16 +2227,6 @@ "zygote_host/zygote_host_impl_linux.h", ] - if (ozone_platform_x11 || use_x11) { - sources += [ - "gpu_data_manager_visual_proxy_ozone_linux.cc", - "gpu_data_manager_visual_proxy_ozone_linux.h", - ] - if (use_x11) { - deps += [ "//ui/base/x:gl" ] - } - } - public_deps += [ "//components/services/font/public/mojom" ] deps += [
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc index b7bf1fd..ee23d97 100644 --- a/content/browser/accessibility/web_contents_accessibility_android.cc +++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -29,6 +29,7 @@ #include "content/public/android/content_jni_headers/WebContentsAccessibilityImpl_jni.h" #include "content/public/common/content_features.h" #include "content/public/common/use_zoom_for_dsf_policy.h" +#include "ui/accessibility/accessibility_features.h" #include "ui/accessibility/ax_assistant_structure.h" #include "ui/events/android/motion_event_android.h" @@ -268,7 +269,8 @@ } void WebContentsAccessibilityAndroid::Enable(JNIEnv* env, - const JavaParamRef<jobject>& obj) { + const JavaParamRef<jobject>& obj, + jboolean screen_reader_mode) { BrowserAccessibilityStateImpl* accessibility_state = BrowserAccessibilityStateImpl::GetInstance(); auto* manager = GetRootBrowserAccessibilityManager(); @@ -282,6 +284,13 @@ return; } + if (features::IsComputeAXModeEnabled()) { + ui::AXMode mode = + screen_reader_mode ? ui::kAXModeComplete : ui::kAXModeBasic; + accessibility_state->AddAccessibilityModeFlags(mode); + return; + } + // Otherwise, enable accessibility globally unless it was // explicitly disallowed by a command-line flag, then enable it for // this WebContents if that succeeded. @@ -300,6 +309,28 @@ } } +void WebContentsAccessibilityAndroid::SetAXMode( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + jboolean screen_reader_mode) { + if (!features::IsComputeAXModeEnabled()) + return; + + BrowserAccessibilityStateImpl* accessibility_state = + BrowserAccessibilityStateImpl::GetInstance(); + + if (screen_reader_mode) { + accessibility_state->AddAccessibilityModeFlags(ui::kAXModeComplete); + } else { + // Remove the mode flags present in kAXModeComplete but not in + // kAXModeBasic, thereby reverting the mode to kAXModeBasic while + // not touching any other flags. + ui::AXMode remove_mode_flags(ui::kAXModeComplete.mode() & + ~ui::kAXModeBasic.mode()); + accessibility_state->RemoveAccessibilityModeFlags(remove_mode_flags); + } +} + bool WebContentsAccessibilityAndroid::ShouldRespectDisplayedPasswordText() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
diff --git a/content/browser/accessibility/web_contents_accessibility_android.h b/content/browser/accessibility/web_contents_accessibility_android.h index 4cf809b..d7b9d16 100644 --- a/content/browser/accessibility/web_contents_accessibility_android.h +++ b/content/browser/accessibility/web_contents_accessibility_android.h
@@ -71,7 +71,12 @@ // Global methods. jboolean IsEnabled(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); - void Enable(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + void Enable(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jboolean screen_reader_mode); + void SetAXMode(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jboolean screen_reader_mode); base::android::ScopedJavaLocalRef<jstring> GetSupportedHtmlElementTypes( JNIEnv* env,
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index f1f6dc64a..058bdd40 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -194,10 +194,6 @@ #include <glib-object.h> #endif -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) -#include "content/browser/gpu_data_manager_visual_proxy_ozone_linux.h" -#endif - #if defined(OS_WIN) #include "media/device_monitors/system_message_window_win.h" #include "sandbox/win/src/process_mitigations.h" @@ -807,15 +803,6 @@ // while avoiding doing so in unit tests by making it explicitly enabled here. GpuDataManagerImpl::GetInstance()->StartUmaTimer(); -// Temporarily used by both Ozone/Linux and X11/Linux. Once X11/Linux goes -// away, will be used only by Ozone/Linux. -// TODO(https://crbug.com/1085700): make sure it's only used by Ozone/Linux. -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) - gpu_data_manager_visual_proxy_ = - std::make_unique<GpuDataManagerVisualProxyOzoneLinux>( - GpuDataManagerImpl::GetInstance()); -#endif - #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) || defined(OS_ANDROID) // Single-process is an unsupported and not fully tested mode, so // don't enable it for official Chrome builds (except on Android).
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 30d6d6f..62acb18 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -108,10 +108,6 @@ class ScreenOrientationDelegate; #endif -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) -class GpuDataManagerVisualProxyOzoneLinux; -#endif - // Implements the main browser loop stages called from BrowserMainRunner. // See comments in browser_main_parts.h for additional info. class CONTENT_EXPORT BrowserMainLoop { @@ -341,10 +337,6 @@ // Members initialized in |PreCreateThreads()| ------------------------------- // Torn down in ShutdownThreadsAndCleanUp. std::unique_ptr<base::MemoryPressureMonitor> memory_pressure_monitor_; -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) - std::unique_ptr<GpuDataManagerVisualProxyOzoneLinux> - gpu_data_manager_visual_proxy_; -#endif // Members initialized in |CreateThreads()| ---------------------------------- std::unique_ptr<BrowserProcessIOThread> io_thread_;
diff --git a/content/browser/compute_pressure/compute_pressure_manager.cc b/content/browser/compute_pressure/compute_pressure_manager.cc index c02638c4c..f2729e7 100644 --- a/content/browser/compute_pressure/compute_pressure_manager.cc +++ b/content/browser/compute_pressure/compute_pressure_manager.cc
@@ -21,6 +21,7 @@ #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "services/network/public/cpp/is_potentially_trustworthy.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/compute_pressure/compute_pressure.mojom.h" namespace content { @@ -68,6 +69,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(frame_id); + if (!base::FeatureList::IsEnabled(blink::features::kComputePressure)) { + mojo::ReportBadMessage("Compute Pressure not enabled"); + return; + } + if (!network::IsOriginPotentiallyTrustworthy(origin)) { mojo::ReportBadMessage("Compute Pressure access from an insecure origin"); return;
diff --git a/content/browser/compute_pressure/compute_pressure_manager_unittest.cc b/content/browser/compute_pressure/compute_pressure_manager_unittest.cc index d8b4f95..7cb20495 100644 --- a/content/browser/compute_pressure/compute_pressure_manager_unittest.cc +++ b/content/browser/compute_pressure/compute_pressure_manager_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/test/scoped_feature_list.h" #include "content/browser/compute_pressure/compute_pressure_test_support.h" #include "content/public/browser/global_routing_id.h" #include "content/test/fake_mojo_message_dispatch_context.h" @@ -16,14 +17,13 @@ #include "mojo/public/cpp/test_support/test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/compute_pressure/compute_pressure.mojom.h" namespace content { class ComputePressureManagerTest : public RenderViewHostImplTestHarness { public: - ComputePressureManagerTest() = default; - void SetUp() override { RenderViewHostImplTestHarness::SetUp(); NavigateAndCommit(kTestUrl); @@ -68,6 +68,8 @@ {0.2, 0.5, 0.8}, {0.5}}; + base::test::ScopedFeatureList scoped_feature_list_; + GlobalFrameRoutingId main_frame_id_; // This member is a std::unique_ptr instead of a plain ComputePressureManager // so it can be replaced inside tests. @@ -212,4 +214,17 @@ blink::mojom::ComputePressureStatus::kNotSupported); } +TEST_F(ComputePressureManagerTest, AddObserver_NoFeature) { + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndDisableFeature(blink::features::kComputePressure); + + FakeMojoMessageDispatchContext fake_dispatch_context; + mojo::test::BadMessageObserver bad_message_observer; + mojo::Remote<blink::mojom::ComputePressureHost> insecure_host; + manager_->BindReceiver(kInsecureOrigin, main_frame_id_, + insecure_host.BindNewPipeAndPassReceiver()); + EXPECT_EQ("Compute Pressure not enabled", + bad_message_observer.WaitForBadMessage()); +} + } // namespace content
diff --git a/content/browser/compute_pressure/compute_pressure_origin_trial_browsertest.cc b/content/browser/compute_pressure/compute_pressure_origin_trial_browsertest.cc new file mode 100644 index 0000000..f4eae2799 --- /dev/null +++ b/content/browser/compute_pressure/compute_pressure_origin_trial_browsertest.cc
@@ -0,0 +1,90 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "base/test/scoped_feature_list.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/public/test/url_loader_interceptor.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +constexpr char kBaseDataDir[] = "content/test/data/compute_pressure"; + +class ComputePressureOriginTrialBrowserTest : public ContentBrowserTest { + public: + ~ComputePressureOriginTrialBrowserTest() override = default; + + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + + // We need to use URLLoaderInterceptor (rather than a EmbeddedTestServer), + // because origin trial token is associated with a fixed origin, whereas + // EmbeddedTestServer serves content on a random port. + interceptor_ = URLLoaderInterceptor::ServeFilesFromDirectoryAtOrigin( + kBaseDataDir, GURL("https://example.test/")); + } + + void TearDownOnMainThread() override { + interceptor_.reset(); + ContentBrowserTest::TearDownOnMainThread(); + } + + bool HasComputePressureApi() { + return EvalJs(shell(), "'ComputePressureObserver' in window").ExtractBool(); + } + + protected: + const GURL kValidTokenUrl{"https://example.test/valid_token.html"}; + const GURL kNoTokenUrl{"https://example.test/no_token.html"}; + + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<content::URLLoaderInterceptor> interceptor_; +}; + +IN_PROC_BROWSER_TEST_F(ComputePressureOriginTrialBrowserTest, + ValidOriginTrialToken) { + ASSERT_TRUE(NavigateToURL(shell(), kValidTokenUrl)); + EXPECT_TRUE(HasComputePressureApi()); +} + +IN_PROC_BROWSER_TEST_F(ComputePressureOriginTrialBrowserTest, + NoOriginTrialToken) { + ASSERT_TRUE(NavigateToURL(shell(), kNoTokenUrl)); + EXPECT_FALSE(HasComputePressureApi()); +} + +class ComputePressureOriginTrialKillSwitchBrowserTest + : public ComputePressureOriginTrialBrowserTest { + public: + ComputePressureOriginTrialKillSwitchBrowserTest() { + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndDisableFeature( + blink::features::kComputePressure); + } +}; + +IN_PROC_BROWSER_TEST_F(ComputePressureOriginTrialKillSwitchBrowserTest, + ValidOriginTrialToken) { + ASSERT_TRUE(NavigateToURL(shell(), kValidTokenUrl)); + EXPECT_FALSE(HasComputePressureApi()); +} + +IN_PROC_BROWSER_TEST_F(ComputePressureOriginTrialKillSwitchBrowserTest, + NoOriginTrialToken) { + ASSERT_TRUE(NavigateToURL(shell(), kNoTokenUrl)); + EXPECT_FALSE(HasComputePressureApi()); +} + +} // namespace + +} // namespace content
diff --git a/content/browser/conversions/conversion_network_sender_impl.cc b/content/browser/conversions/conversion_network_sender_impl.cc index 246635c6..b1ba2ec 100644 --- a/content/browser/conversions/conversion_network_sender_impl.cc +++ b/content/browser/conversions/conversion_network_sender_impl.cc
@@ -196,15 +196,23 @@ network::SimpleURLLoader* loader = it->get(); // Consider a non-200 HTTP code as a non-internal error. - bool internal_ok = loader->NetError() == net::OK || - loader->NetError() == net::ERR_HTTP_RESPONSE_CODE_FAILURE; - bool external_ok = headers && headers->response_code() == net::HTTP_OK; + int net_error = loader->NetError(); + bool internal_ok = + net_error == net::OK || net_error == net::ERR_HTTP_RESPONSE_CODE_FAILURE; + + int response_code = headers ? headers->response_code() : -1; + bool external_ok = response_code == net::HTTP_OK; Status status = internal_ok && external_ok ? Status::kOk : !internal_ok ? Status::kInternalError : Status::kExternalError; base::UmaHistogramEnumeration("Conversions.ReportStatus", status); + // Since net errors are always negative and HTTP errors are always positive, + // it is fine to combine these in a single histogram. + base::UmaHistogramSparse("Conversions.Report.HttpResponseOrNetErrorCode", + internal_ok ? response_code : net_error); + if (loader->GetNumRetries() > 0) { base::UmaHistogramBoolean("Conversions.ReportRetrySucceed", status == Status::kOk);
diff --git a/content/browser/conversions/conversion_network_sender_impl_unittest.cc b/content/browser/conversions/conversion_network_sender_impl_unittest.cc index e6f9e05..a5e7f423 100644 --- a/content/browser/conversions/conversion_network_sender_impl_unittest.cc +++ b/content/browser/conversions/conversion_network_sender_impl_unittest.cc
@@ -282,6 +282,8 @@ kReportUrl, "")); // kOk = 0. histograms.ExpectUniqueSample("Conversions.ReportStatus", 0, 1); + histograms.ExpectUniqueSample( + "Conversions.Report.HttpResponseOrNetErrorCode", net::HTTP_OK, 1); } // Internal error. { @@ -294,6 +296,8 @@ network::mojom::URLResponseHead::New(), std::string())); // kInternalError = 1. histograms.ExpectUniqueSample("Conversions.ReportStatus", 1, 1); + histograms.ExpectUniqueSample( + "Conversions.Report.HttpResponseOrNetErrorCode", net::ERR_FAILED, 1); } { base::HistogramTester histograms; @@ -303,6 +307,9 @@ kReportUrl, std::string(), net::HTTP_UNAUTHORIZED)); // kExternalError = 2. histograms.ExpectUniqueSample("Conversions.ReportStatus", 2, 1); + histograms.ExpectUniqueSample( + "Conversions.Report.HttpResponseOrNetErrorCode", net::HTTP_UNAUTHORIZED, + 1); } }
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index 82c37883..329131b 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -1186,9 +1186,12 @@ case gpu::GpuMode::HARDWARE_VULKAN: use_gl = browser_command_line->GetSwitchValueASCII(switches::kUseGL); break; - case gpu::GpuMode::SWIFTSHADER: - use_gl = gl::kGLImplementationSwiftShaderForWebGLName; - break; + case gpu::GpuMode::SWIFTSHADER: { + // This setting makes WebGL run on legacy SwiftShader GL when true and + // SwANGLE when false. + bool legacy_software_gl = true; + gl::SetSoftwareWebGLCommandLineSwitches(command_line, legacy_software_gl); + } break; default: use_gl = gl::kGLImplementationDisabledName; }
diff --git a/content/browser/gpu_data_manager_visual_proxy_ozone_linux.cc b/content/browser/gpu_data_manager_visual_proxy_ozone_linux.cc deleted file mode 100644 index 4dbb470..0000000 --- a/content/browser/gpu_data_manager_visual_proxy_ozone_linux.cc +++ /dev/null
@@ -1,107 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/gpu_data_manager_visual_proxy_ozone_linux.h" - -#include "base/command_line.h" -#include "content/browser/gpu/gpu_process_host.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/content_features.h" -#include "ui/gfx/switches.h" - -#if defined(USE_OZONE) -#include "ui/base/ui_base_features.h" -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/platform_gl_egl_utility.h" -#endif - -#if defined(USE_X11) -#include "ui/base/x/x11_gl_egl_utility.h" // nogncheck -#endif - -namespace content { - -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) -namespace { - -void ShutdownGpuOnProcessThread() { - // The GPU process sent back bad visuals, which should never happen. - auto* gpu_process_host = - GpuProcessHost::Get(GPU_PROCESS_KIND_SANDBOXED, false); - if (gpu_process_host) - gpu_process_host->ForceShutdown(); -} - -} // namespace -#endif // defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) - -GpuDataManagerVisualProxyOzoneLinux::GpuDataManagerVisualProxyOzoneLinux( - GpuDataManagerImpl* gpu_data_manager) - : gpu_data_manager_(gpu_data_manager) { - if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) - scoped_observer_.Observe(gpu_data_manager_); -} - -GpuDataManagerVisualProxyOzoneLinux::~GpuDataManagerVisualProxyOzoneLinux() = - default; - -void GpuDataManagerVisualProxyOzoneLinux::OnGpuInfoUpdate() { - OnUpdate(); -} - -void GpuDataManagerVisualProxyOzoneLinux::OnGpuExtraInfoUpdate() { - OnUpdate(); -} - -void GpuDataManagerVisualProxyOzoneLinux::OnUpdate() { -#if defined(USE_OZONE) - // Early return for Ozone/non-X11. Otherwise UpdateVisualsOnGpuInfoChanged() - // will return false, thus terminating the GPU process and ruining things. - if (features::IsUsingOzonePlatform() && - !ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility()) { - return; - } -#endif - -#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) - gpu::GPUInfo gpu_info = gpu_data_manager_->GetGPUInfo(); - gfx::GpuExtraInfo gpu_extra_info = gpu_data_manager_->GetGpuExtraInfo(); - if (!UpdateVisualsOnGpuInfoChanged( - gpu_info.software_rendering || - !gpu_data_manager_->GpuAccessAllowed(nullptr), - gpu_extra_info.system_visual, gpu_extra_info.rgba_visual)) { - if (base::FeatureList::IsEnabled(features::kProcessHostOnUI)) { - ShutdownGpuOnProcessThread(); - } else { - GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&ShutdownGpuOnProcessThread)); - } - } -#endif -} - -bool GpuDataManagerVisualProxyOzoneLinux::UpdateVisualsOnGpuInfoChanged( - bool software_rendering, - x11::VisualId default_visual_id, - x11::VisualId transparent_visual_id) { -#if defined(USE_OZONE) - if (features::IsUsingOzonePlatform() && - ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility()) { - return ui::OzonePlatform::GetInstance() - ->GetPlatformGLEGLUtility() - ->UpdateVisualsOnGpuInfoChanged( - software_rendering, static_cast<uint32_t>(default_visual_id), - static_cast<uint32_t>(transparent_visual_id)); - } -#endif -#if defined(USE_X11) - return ui::UpdateVisualsOnGpuInfoChanged( - software_rendering, default_visual_id, transparent_visual_id); -#endif - NOTREACHED() << "Only X11 may invoke this!"; - return false; -} - -} // namespace content
diff --git a/content/browser/gpu_data_manager_visual_proxy_ozone_linux.h b/content/browser/gpu_data_manager_visual_proxy_ozone_linux.h deleted file mode 100644 index 86b63d66..0000000 --- a/content/browser/gpu_data_manager_visual_proxy_ozone_linux.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_GPU_DATA_MANAGER_VISUAL_PROXY_OZONE_LINUX_H_ -#define CONTENT_BROWSER_GPU_DATA_MANAGER_VISUAL_PROXY_OZONE_LINUX_H_ - -#include "base/scoped_observation.h" -#include "content/browser/gpu/gpu_data_manager_impl.h" -#include "content/public/browser/gpu_data_manager_observer.h" -#include "ui/gfx/gpu_extra_info.h" - -namespace content { - -// Forwards GPUInfo updates to ui::XVisualManager on X11 (will be removed as -// soon as Ozone is default on Linux) or PlatformEGLGLUtility. -class GpuDataManagerVisualProxyOzoneLinux : public GpuDataManagerObserver { - public: - explicit GpuDataManagerVisualProxyOzoneLinux( - GpuDataManagerImpl* gpu_data_manager); - GpuDataManagerVisualProxyOzoneLinux( - const GpuDataManagerVisualProxyOzoneLinux&) = delete; - GpuDataManagerVisualProxyOzoneLinux& operator=( - const GpuDataManagerVisualProxyOzoneLinux&) = delete; - ~GpuDataManagerVisualProxyOzoneLinux() override; - - void OnGpuInfoUpdate() override; - void OnGpuExtraInfoUpdate() override; - - private: - void OnUpdate(); - bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - x11::VisualId default_visual_id, - x11::VisualId transparent_visual_id); - - GpuDataManagerImpl* gpu_data_manager_; - base::ScopedObservation<GpuDataManagerImpl, GpuDataManagerObserver> - scoped_observer_{this}; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_GPU_DATA_MANAGER_VISUAL_PROXY_OZONE_LINUX_H_
diff --git a/content/browser/interest_group/DEPS b/content/browser/interest_group/DEPS index 269a2bd..be1d75fb 100644 --- a/content/browser/interest_group/DEPS +++ b/content/browser/interest_group/DEPS
@@ -1,3 +1,11 @@ include_rules = [ "+content/services/auction_worklet/public/mojom", ] + +specific_include_rules = { + # The AuctionRunnerTests have integration tests that directly instantiate an + # in-process auction_worklet service. + "auction_runner_unittest\.cc": [ + "+content/services/auction_worklet", + ], +} \ No newline at end of file
diff --git a/content/browser/interest_group/ad_auction.cc b/content/browser/interest_group/ad_auction.cc index 29effe4..4ef9d7a 100644 --- a/content/browser/interest_group/ad_auction.cc +++ b/content/browser/interest_group/ad_auction.cc
@@ -15,13 +15,14 @@ #include "base/strings/stringprintf.h" #include "content/browser/devtools/devtools_instrumentation.h" #include "content/browser/interest_group/ad_auction_service_impl.h" +#include "content/browser/interest_group/auction_runner.h" #include "content/browser/interest_group/auction_url_loader_factory_proxy.h" #include "content/browser/interest_group/interest_group_manager.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/content_client.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" @@ -67,46 +68,6 @@ return true; } -struct ValidatedResult { - bool is_valid_auction_result = false; - std::string ad_json; -}; - -ValidatedResult ValidateAuctionResult( - const std::vector<auction_worklet::mojom::BiddingInterestGroupPtr>& bidders, - const GURL& render_url, - const url::Origin& owner, - const std::string& name) { - ValidatedResult result; - if (!render_url.is_valid() || !render_url.SchemeIs(url::kHttpsScheme)) - return result; - - for (const auto& bidder : bidders) { - // Auction winner must be one of the bidders and bidder must have ads. - if (bidder->group->owner != owner || bidder->group->name != name || - !bidder->group->ads) { - continue; - } - // `render_url` must be one of the winning bidder's ads. - for (const auto& ad : bidder->group->ads.value()) { - if (ad->render_url == render_url) { - result.is_valid_auction_result = true; - if (ad->metadata) { - //`metadata` is already in JSON so no quotes are needed. - result.ad_json = base::StringPrintf( - R"({"render_url":"%s","metadata":%s})", render_url.spec().c_str(), - ad->metadata.value().c_str()); - } else { - result.ad_json = base::StringPrintf(R"({"render_url":"%s"})", - render_url.spec().c_str()); - } - return result; - } - } - } - return result; -} - } // namespace AdAuction::AdAuction(AdAuctionServiceImpl* ad_auction_service, @@ -157,13 +118,6 @@ ReadNextInterestGroup(); } -void AdAuction::OnServiceCrash() { - // This cancels any pending async callbacks. - weak_ptr_factory_.InvalidateWeakPtrs(); - - OnAuctionFailed(); -} - void AdAuction::ReadNextInterestGroup() { DCHECK(!pending_buyers_.empty()); @@ -201,39 +155,31 @@ DCHECK(pending_buyers_.empty()); DCHECK(!bidders_.empty()); + // TODO(mmenke): This should be top frame origin, not frame origin. auto browser_signals = auction_worklet::mojom::BrowserSignals::New( ad_auction_service_->origin(), config_->seller); - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; - url_loader_factory_proxy_ = std::make_unique<AuctionURLLoaderFactoryProxy>( - url_loader_factory.InitWithNewPipeAndPassReceiver(), - base::BindRepeating(&AdAuctionServiceImpl::GetFrameURLLoaderFactory, - base::Unretained(ad_auction_service_)), - base::BindRepeating(&AdAuctionServiceImpl::GetTrustedURLLoaderFactory, - base::Unretained(ad_auction_service_)), - browser_signals->top_frame_origin, *config_, bidders_); - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders_copy; bidders_copy.reserve(bidders_.size()); for (auto& bidder : bidders_) bidders_copy.emplace_back(bidder.Clone()); // `config_` is no longer needed after this point, so pass ownership of it - // over to the worklet, instead of copying it. - ad_auction_service_->GetWorkletService()->RunAuction( - std::move(url_loader_factory), std::move(config_), - std::move(bidders_copy), std::move(browser_signals), + // over to the AuctionRunner, instead of copying it. + auction_runner_ = AuctionRunner::CreateAndStart( + ad_auction_service_, std::move(config_), std::move(bidders_copy), + std::move(browser_signals), ad_auction_service_->origin(), base::BindOnce(&AdAuction::WorkletComplete, weak_ptr_factory_.GetWeakPtr())); } -void AdAuction::WorkletComplete( - const GURL& render_url, - const url::Origin& owner, - const std::string& name, - auction_worklet::mojom::WinningBidderReportPtr bidder_report, - auction_worklet::mojom::SellerReportPtr seller_report, - const std::vector<std::string>& errors) { +void AdAuction::WorkletComplete(const GURL& render_url, + const std::string& ad_metadata, + const url::Origin& owner, + const std::string& name, + const GURL& bidder_report_url, + const GURL& seller_report_url, + const std::vector<std::string>& errors) { DCHECK(callback_); // Forward debug information to devtools. @@ -244,28 +190,21 @@ error); } - // Check if returned winner's information is valid. - ValidatedResult result = - ValidateAuctionResult(bidders_, render_url, owner, name); - if (!result.is_valid_auction_result) { + if (!render_url.is_valid()) { OnAuctionFailed(); return; } - absl::optional<GURL> bidder_report_url; - if (bidder_report->report_requested && bidder_report->report_url.is_valid() && - bidder_report->report_url.SchemeIs(url::kHttpsScheme)) { - bidder_report_url = bidder_report->report_url; - } + absl::optional<GURL> opt_bidder_report_url; + if (bidder_report_url.is_valid()) + opt_bidder_report_url = bidder_report_url; - absl::optional<GURL> seller_report_url; - if (seller_report->success && seller_report->report_url.is_valid() && - seller_report->report_url.SchemeIs(url::kHttpsScheme)) { - seller_report_url = seller_report->report_url; - } + absl::optional<GURL> opt_seller_report_url; + if (seller_report_url.is_valid()) + opt_seller_report_url = seller_report_url; ad_auction_service_->GetInterestGroupManager()->RecordInterestGroupWin( - owner, name, result.ad_json); + owner, name, ad_metadata); // TODO(qingxin): Decide if we should record a bid if the auction fails, or // the interest group doesn't make a bid. for (const auto& bidder : bidders_) { @@ -273,8 +212,8 @@ bidder->group->owner, bidder->group->name); } - std::move(callback_).Run(this, render_url, bidder_report_url, - seller_report_url); + std::move(callback_).Run(this, render_url, opt_bidder_report_url, + opt_seller_report_url); } void AdAuction::OnAuctionFailed() {
diff --git a/content/browser/interest_group/ad_auction.h b/content/browser/interest_group/ad_auction.h index 05105fae13..bd066b5 100644 --- a/content/browser/interest_group/ad_auction.h +++ b/content/browser/interest_group/ad_auction.h
@@ -11,7 +11,7 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-forward.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" #include "url/gurl.h" @@ -20,7 +20,7 @@ namespace content { class AdAuctionServiceImpl; -class AuctionURLLoaderFactoryProxy; +class AuctionRunner; // Class for running a single FLEDGE auction. class AdAuction { @@ -43,10 +43,6 @@ // May invoke `AuctionCompleteCallback` synchronously. void StartAuction(); - // Must be called when the worklet service crashes, to ensure the renderer's - // callback is invoked. Synchronously invokes AuctionCompleteCallback. - void OnServiceCrash(); - private: // Retrieves the next interest group in `pending_buyers_` from storage, // removing it from the vector. OnInterestGroupRead() will be invoked @@ -66,13 +62,13 @@ // // Validates the results, reports them to `callback_`, and updates the // InterestGroupStorage as needed. - void WorkletComplete( - const GURL& render_url, - const url::Origin& owner, - const std::string& name, - auction_worklet::mojom::WinningBidderReportPtr bidder_report, - auction_worklet::mojom::SellerReportPtr seller_report, - const std::vector<std::string>& errors); + void WorkletComplete(const GURL& render_url, + const std::string& ad_metadata, + const url::Origin& owner, + const std::string& name, + const GURL& bidder_report_url, + const GURL& seller_report_url, + const std::vector<std::string>& errors); // Invokes `callback_` with empty parameters, to inform it of the failure. void OnAuctionFailed(); @@ -93,8 +89,7 @@ // from interest group storage. std::vector<url::Origin> pending_buyers_; - // Proxy used for requests from the worklet process. - std::unique_ptr<AuctionURLLoaderFactoryProxy> url_loader_factory_proxy_; + std::unique_ptr<AuctionRunner> auction_runner_; base::WeakPtrFactory<AdAuction> weak_ptr_factory_{this}; };
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc index 8518cdc..3d676b2f 100644 --- a/content/browser/interest_group/ad_auction_service_impl.cc +++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -180,8 +180,6 @@ ServiceProcessHost::Options() .WithDisplayName("Auction Worklet Service") .Pass()); - auction_worklet_service_.set_disconnect_handler(base::BindOnce( - &AdAuctionServiceImpl::OnWorkletServiceCrash, base::Unretained(this))); } return auction_worklet_service_.get(); } @@ -214,14 +212,4 @@ FetchReport(factory, *seller_report_url, origin()); } -void AdAuctionServiceImpl::OnWorkletServiceCrash() { - // Each loop iteration calls on OnServiceCrash() on a single element of - // `auctions_`, which should result in it being immediately deleted. Since the - // loop modifies `auctions_`, need to be careful not to hold onto an iterator - // for the removed element, which this loop does by checking if `auctions_` is - // empty, rather than using a for loop. - while (!auctions_.empty()) - (*auctions_.begin())->OnServiceCrash(); -} - } // namespace content
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h index 56fdf26..0acf619 100644 --- a/content/browser/interest_group/ad_auction_service_impl.h +++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -10,6 +10,7 @@ #include <string> #include "base/containers/unique_ptr_adapters.h" +#include "content/browser/interest_group/auction_runner.h" #include "content/browser/interest_group/interest_group_manager.h" #include "content/common/content_export.h" #include "content/public/browser/frame_service_base.h" @@ -29,7 +30,8 @@ // Implements the AdAuctionService service called by Blink code. class CONTENT_EXPORT AdAuctionServiceImpl final - : public FrameServiceBase<blink::mojom::AdAuctionService> { + : public FrameServiceBase<blink::mojom::AdAuctionService>, + public AuctionRunner::Delegate { public: // Factory method for creating an instance of this interface that is // bound to the lifetime of the frame or receiver (whichever is shorter). @@ -43,19 +45,10 @@ InterestGroupManager* GetInterestGroupManager(); - // Returns an untrusted URLLoaderFactory created by the RenderFrameHost, - // suitable for loading URLs like subresources. Caches the factory in - // `frame_url_loader_factory_` for reuse. - network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory(); - - // Returns a trusted URLLoaderFactory. Consumers should set - // ResourceRequest::TrustedParams to specify a NetworkIsolationKey when using - // the returned factory. Caches the factory in `trusted_url_loader_factory_` - // for reuse. - network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory(); - - // Launches the worklet service, if needed. - auction_worklet::mojom::AuctionWorkletService* GetWorkletService(); + // AuctionRunner::Delegate implementation: + network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override; + network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() override; + auction_worklet::mojom::AuctionWorkletService* GetWorkletService() override; using FrameServiceBase::origin; using FrameServiceBase::render_frame_host; @@ -77,8 +70,6 @@ absl::optional<GURL> bidder_report_url, absl::optional<GURL> seller_report_url); - void OnWorkletServiceCrash(); - // This must be above `auction_worklet_service_`, since auctions may own // callbacks over the AuctionWorkletService pipe, and mojo pipes must be // destroyed before any callbacks that are bound to them.
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc new file mode 100644 index 0000000..8955c24 --- /dev/null +++ b/content/browser/interest_group/auction_runner.cc
@@ -0,0 +1,453 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/interest_group/auction_runner.h" + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/callback_forward.h" +#include "base/strings/strcat.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "content/browser/interest_group/auction_url_loader_factory_proxy.h" +#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" +#include "net/base/escape.h" +#include "services/network/public/mojom/url_loader_factory.mojom-forward.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" +#include "url/gurl.h" + +namespace content { + +namespace { + +// All URLs received from worklets must be valid HTTPS URLs. It's up to callers +// to call ReportBadMessage() on invalid URLs. +bool IsUrlValid(const GURL& url) { + return url.is_valid() && url.SchemeIs(url::kHttpsScheme); +} + +// Validates that `bid` is valid and, if it is, returns the InterestGroupAd +// corresponding to the bid. Returns nullptr and calls ReportBadMessage() if +// not. If non-null, the returned pointer will point at the winning +// blink::mojom::InterestGroupAd within `bid`. +blink::mojom::InterestGroupAd* ValidateBidAndGetAd( + const auction_worklet::mojom::BidderWorkletBid& bid, + const blink::mojom::InterestGroup& interest_group) { + if (bid.bid <= 0 || std::isnan(bid.bid) || !std::isfinite(bid.bid)) { + mojo::ReportBadMessage("Invalid bid value"); + return nullptr; + } + + if (bid.bid_duration < base::TimeDelta()) { + mojo::ReportBadMessage("Invalid bid duration"); + return nullptr; + } + + // This should be a subset of the next case, but best to be careful. + if (!IsUrlValid(bid.render_url)) { + mojo::ReportBadMessage("Invalid bid render URL"); + return nullptr; + } + + // Reject URLs not listed in the interest group. + for (const auto& ad : interest_group.ads.value()) { + if (ad->render_url == bid.render_url) { + return ad.get(); + } + } + + mojo::ReportBadMessage("Bid render URL must be an ad URL"); + return nullptr; +} + +} // namespace + +AuctionRunner::BidState::BidState() = default; +AuctionRunner::BidState::~BidState() = default; +AuctionRunner::BidState::BidState(BidState&&) = default; + +std::unique_ptr<AuctionRunner> AuctionRunner::CreateAndStart( + Delegate* delegate, + blink::mojom::AuctionAdConfigPtr auction_config, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + auction_worklet::mojom::BrowserSignalsPtr browser_signals, + const url::Origin& frame_origin, + RunAuctionCallback callback) { + std::unique_ptr<AuctionRunner> instance(new AuctionRunner( + delegate, std::move(auction_config), std::move(bidders), + std::move(browser_signals), frame_origin, std::move(callback))); + instance->StartBidding(); + return instance; +} + +AuctionRunner::AuctionRunner( + Delegate* delegate, + blink::mojom::AuctionAdConfigPtr auction_config, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + auction_worklet::mojom::BrowserSignalsPtr browser_signals, + const url::Origin& frame_origin, + RunAuctionCallback callback) + : delegate_(delegate), + auction_config_(std::move(auction_config)), + bidders_(std::move(bidders)), + browser_signals_(std::move(browser_signals)), + frame_origin_(frame_origin), + callback_(std::move(callback)) {} + +AuctionRunner::~AuctionRunner() = default; + +void AuctionRunner::StartBidding() { + // Auctions are only run when there are bidders participating. As-is, and + // empty bidder vector here would result in synchronously calling back into + // the creator, which isn't allowed. + DCHECK(!bidders_.empty()); + + outstanding_bids_ = bidders_.size(); + bid_states_.resize(outstanding_bids_); + + for (int bid_index = 0; bid_index < outstanding_bids_; ++bid_index) { + const auction_worklet::mojom::BiddingInterestGroupPtr& bidder = + bidders_[bid_index]; + BidState* bid_state = &bid_states_[bid_index]; + bid_state->bidder = bidder.get(); + + // Assemble list of URLs the bidder can request. + + // TODO(mmenke): This largely duplicates logic in the auction worklet + // service. Avoid duplicating code. + absl::optional<GURL> trusted_bidding_signals_full_url; + if (bid_state->bidder->group->trusted_bidding_signals_url && + bid_state->bidder->group->trusted_bidding_signals_keys) { + std::string query_params = + "hostname=" + net::EscapeQueryParamValue( + browser_signals_->top_frame_origin.host(), true); + query_params += "&keys="; + bool first_key = true; + for (const auto& key : + *bid_state->bidder->group->trusted_bidding_signals_keys) { + if (first_key) { + first_key = false; + } else { + query_params.append(","); + } + query_params.append(net::EscapeQueryParamValue(key, true)); + } + + GURL::Replacements replacements; + replacements.SetQueryStr(query_params); + trusted_bidding_signals_full_url = + bid_state->bidder->group->trusted_bidding_signals_url + ->ReplaceComponents(replacements); + } + + mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; + bid_state->url_loader_factory_ = + std::make_unique<AuctionURLLoaderFactoryProxy>( + url_loader_factory.InitWithNewPipeAndPassReceiver(), + base::BindRepeating(&Delegate::GetTrustedURLLoaderFactory, + base::Unretained(delegate_)), + frame_origin_, false /* use_cors */, + bid_state->bidder->group->bidding_url.value_or(GURL()), + trusted_bidding_signals_full_url); + + delegate_->GetWorkletService()->LoadBidderWorkletAndGenerateBid( + bid_state->bidder_worklet.BindNewPipeAndPassReceiver(), + std::move(url_loader_factory), bidder->Clone(), + auction_config_->auction_signals, PerBuyerSignals(bid_state), + browser_signals_->top_frame_origin, browser_signals_->seller, + auction_start_time_, + base::BindOnce(&AuctionRunner::OnGenerateBidComplete, + weak_ptr_factory_.GetWeakPtr(), bid_state)); + bid_state->bidder_worklet.set_disconnect_handler( + base::BindOnce(&AuctionRunner::OnGenerateBidCrashed, + weak_ptr_factory_.GetWeakPtr(), bid_state)); + } + + // Also initiate the script fetch for the seller script. + mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; + seller_url_loader_factory_ = std::make_unique<AuctionURLLoaderFactoryProxy>( + url_loader_factory.InitWithNewPipeAndPassReceiver(), + base::BindRepeating(&Delegate::GetFrameURLLoaderFactory, + base::Unretained(delegate_)), + frame_origin_, true /* use_cors */, auction_config_->decision_logic_url); + delegate_->GetWorkletService()->LoadSellerWorklet( + seller_worklet_.BindNewPipeAndPassReceiver(), + std::move(url_loader_factory), auction_config_->decision_logic_url, + base::BindOnce(&AuctionRunner::OnSellerWorkletLoaded, + weak_ptr_factory_.GetWeakPtr())); + // Fail auction if the seller worklet pipe is disconnected. + seller_worklet_.set_disconnect_handler(base::BindOnce( + &AuctionRunner::FailAuctionWithError, weak_ptr_factory_.GetWeakPtr(), + base::StrCat({auction_config_->decision_logic_url.spec(), " crashed."}))); +} + +void AuctionRunner::OnGenerateBidCrashed(BidState* state) { + OnGenerateBidComplete(state, auction_worklet::mojom::BidderWorkletBidPtr(), + std::vector<std::string>{base::StrCat( + {state->bidder->group->bidding_url->spec(), + " crashed while trying to run generateBid()."})}); +} + +void AuctionRunner::OnGenerateBidComplete( + BidState* state, + auction_worklet::mojom::BidderWorkletBidPtr bid, + const std::vector<std::string>& errors) { + DCHECK(!state->bid_result); + DCHECK_GT(outstanding_bids_, 0); + + --outstanding_bids_; + + errors_.insert(errors_.end(), errors.begin(), errors.end()); + + // Ignore invalid bids. + if (bid) { + state->bid_ad = ValidateBidAndGetAd(*bid, *state->bidder->group); + if (!state->bid_ad) + bid.reset(); + } + + // On failure, close the worklet pipe. On success, clear the disconnect + // handler - crashed bidders only matters if it's the winning bidder that + // crashed. That's checked for at the end of the auction. + if (!bid) { + state->bidder_worklet.reset(); + } else { + state->bidder_worklet.set_disconnect_handler(base::OnceClosure()); + } + + state->bid_result = std::move(bid); + + if (ReadyToScore()) + ScoreOne(); +} + +void AuctionRunner::OnSellerWorkletLoaded( + bool load_result, + const std::vector<std::string>& errors) { + errors_.insert(errors_.end(), errors.begin(), errors.end()); + + if (load_result) { + seller_loaded_ = true; + if (ReadyToScore()) + ScoreOne(); + } else { + // Failed to load the seller/auction script --- nothing useful can be + // done, so abort, possibly cancelling other fetches, so we don't waste + // time. + FailAuction(); + } +} + +void AuctionRunner::ScoreOne() { + size_t num_bidders = bid_states_.size(); + + // Find next valid bid to score, if any. + while (seller_considering_ < num_bidders) { + BidState* bid_state = &bid_states_[seller_considering_]; + + // Skip over bidders that produced no valid bid. + if (!bid_state->bid_result) { + ++seller_considering_; + continue; + } + + ScoreBid(bid_state); + return; + } + + DCHECK_EQ(seller_considering_, num_bidders); + CompleteAuction(); +} + +void AuctionRunner::ScoreBid(const BidState* state) { + seller_worklet_->ScoreAd( + state->bid_result->ad, state->bid_result->bid, auction_config_.Clone(), + browser_signals_->top_frame_origin, state->bidder->group->owner, + AdRenderFingerprint(state), + state->bid_result->bid_duration.InMilliseconds(), + base::BindOnce(&AuctionRunner::OnBidScored, + weak_ptr_factory_.GetWeakPtr())); +} + +void AuctionRunner::OnBidScored(double score, + const std::vector<std::string>& errors) { + bid_states_[seller_considering_].seller_score = score; + errors_.insert(errors_.end(), errors.begin(), errors.end()); + ++seller_considering_; + ScoreOne(); +} + +std::string AuctionRunner::AdRenderFingerprint(const BidState* state) { + // TODO(morlovich): "Eventually this fingerprint can be a hash of the ad web + // bundle, but while rendering still uses the network, it should just be a + // hash of the rendering URL." + // + return "#####"; +} + +absl::optional<std::string> AuctionRunner::PerBuyerSignals( + const BidState* state) { + if (auction_config_->per_buyer_signals.has_value()) { + auto it = auction_config_->per_buyer_signals.value().find( + state->bidder->group->owner); + if (it != auction_config_->per_buyer_signals.value().end()) + return it->second; + } + return absl::nullopt; +} + +void AuctionRunner::CompleteAuction() { + double best_bid_score = 0.0; + BidState* best_bid = nullptr; + // TODO(morlovich): What if there is a tie? + for (BidState& bid_state : bid_states_) { + if (bid_state.seller_score > best_bid_score) { + best_bid_score = bid_state.seller_score; + best_bid = &bid_state; + } + } + + if (best_bid) { + // Will eventually send a report to the seller and clean up `this`. + ReportSellerResult(best_bid); + } else { + FailAuction(); + } +} + +void AuctionRunner::ReportSellerResult(BidState* best_bid) { + DCHECK(best_bid->bid_result); + DCHECK_GT(best_bid->seller_score, 0); + seller_worklet_->ReportResult( + auction_config_.Clone(), browser_signals_->top_frame_origin, + best_bid->bidder->group->owner, best_bid->bid_result->render_url, + AdRenderFingerprint(best_bid), best_bid->bid_result->bid, + best_bid->seller_score, + base::BindOnce(&AuctionRunner::OnReportSellerResultComplete, + weak_ptr_factory_.GetWeakPtr(), best_bid)); +} + +void AuctionRunner::OnReportSellerResultComplete( + BidState* best_bid, + const absl::optional<std::string>& signals_for_winner, + const absl::optional<GURL>& seller_report_url, + const std::vector<std::string>& errors) { + signals_for_winner_ = signals_for_winner; + seller_report_url_ = seller_report_url; + errors_.insert(errors_.end(), errors.begin(), errors.end()); + + absl::optional<GURL> opt_bidder_report_url; + if (seller_report_url && !IsUrlValid(*seller_report_url)) { + mojo::ReportBadMessage("Invalid seller report URL"); + FailAuction(); + return; + } + + ReportBidWin(best_bid); +} + +void AuctionRunner::ReportBidWin(BidState* best_bid) { + CHECK(best_bid->bid_result); + std::string signals_for_winner_arg; + // TODO(mmenke): It's unclear what should happen here if + // `signals_for_winner_` is null. As-is, an empty string will result in the + // BidderWorklet's ReportWin() method failing, since it's not valid JSON. + if (signals_for_winner_) + signals_for_winner_arg = *signals_for_winner_; + + // Fail the auction if the winning bidder process has crashed. + // + // TODO(mmenke): Be smarter about process crashes in general. Even without + // the report URL, can display the ad and report to the seller (though will + // need to think more about that case). + // + // TODO(mmenke): Make this FailAuction call (And likely others as well) add + // a failure to `messages_`. + if (!best_bid->bidder_worklet.is_connected()) { + FailAuctionWithError( + base::StrCat({best_bid->bidder->group->bidding_url->spec(), + " crashed while idle."})); + return; + } + + best_bid->bidder_worklet->ReportWin( + signals_for_winner_arg, best_bid->bid_result->render_url, + AdRenderFingerprint(best_bid), best_bid->bid_result->bid, + base::BindOnce(&AuctionRunner::OnReportBidWinComplete, + weak_ptr_factory_.GetWeakPtr(), best_bid)); + best_bid->bidder_worklet.set_disconnect_handler(base::BindOnce( + &AuctionRunner::FailAuctionWithError, weak_ptr_factory_.GetWeakPtr(), + base::StrCat({best_bid->bidder->group->bidding_url->spec(), + " crashed while trying to run reportWin()."}))); +} + +void AuctionRunner::OnReportBidWinComplete( + const BidState* best_bid, + const absl::optional<GURL>& bidder_report_url, + const std::vector<std::string>& errors) { + if (bidder_report_url && !IsUrlValid(*bidder_report_url)) { + mojo::ReportBadMessage("Invalid bidder report URL"); + FailAuction(); + return; + } + + bidder_report_url_ = bidder_report_url; + errors_.insert(errors_.end(), errors.begin(), errors.end()); + ReportSuccess(best_bid); +} + +void AuctionRunner::FailAuction() { + DCHECK(callback_); + ClosePipes(); + + std::move(callback_).Run(GURL(), std::string(), url::Origin(), std::string(), + GURL(), GURL(), errors_); +} + +void AuctionRunner::FailAuctionWithError(std::string error) { + errors_.emplace_back(std::move(error)); + FailAuction(); +} + +void AuctionRunner::ReportSuccess(const BidState* state) { + DCHECK(callback_); + DCHECK(state->bid_result); + ClosePipes(); + + std::string ad_metadata; + if (state->bid_ad->metadata) { + //`metadata` is already in JSON so no quotes are needed. + ad_metadata = + base::StringPrintf(R"({"render_url":"%s","metadata":%s})", + state->bid_result->render_url.spec().c_str(), + state->bid_ad->metadata.value().c_str()); + } else { + ad_metadata = base::StringPrintf( + R"({"render_url":"%s"})", state->bid_result->render_url.spec().c_str()); + } + + std::move(callback_).Run( + state->bid_result->render_url, ad_metadata, state->bidder->group->owner, + state->bidder->group->name, + bidder_report_url_.has_value() ? *bidder_report_url_ : GURL(), + seller_report_url_.has_value() ? *seller_report_url_ : GURL(), errors_); +} + +void AuctionRunner::ClosePipes() { + // This is needed in addition to closing worklet pipes in order to ignore + // worklet creation callbacks. + weak_ptr_factory_.InvalidateWeakPtrs(); + + for (BidState& bid_state : bid_states_) { + bid_state.bidder_worklet.reset(); + } + seller_worklet_.reset(); +} + +} // namespace content
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h new file mode 100644 index 0000000..569aca3 --- /dev/null +++ b/content/browser/interest_group/auction_runner.h
@@ -0,0 +1,255 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_ +#define CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "content/common/content_export.h" +#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" +#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" +#include "services/network/public/mojom/url_loader_factory.mojom-forward.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" +#include "url/gurl.h" + +namespace content { + +class AuctionURLLoaderFactoryProxy; + +// An AuctionRunner loads and runs the bidder and seller worklets, along with +// their reporting phases and produces the result via a callback. +// +// At present it initiates all fetches in parallel, running all bidder scripts +// once they and any trusted signals they need are ready, then when all bids are +// in runs all the scoring, and finally the reporting worklets. +// +// TODO(morlovich): There is no need to wait for all bidders to finish to start +// scoring. +// +// TODO(mmenke): Merge this with `ad_auction`, and provide worklet-specific +// URLLoaderFactories. +// +// TODO(mmenke): Add checking of values returned by auctions (e.g., for bids <= +// 0). +class CONTENT_EXPORT AuctionRunner { + public: + // Invoked when a FLEDGE auction is complete. + // + // `render_url` URL of auction winning ad to render. + // An empty URL is used if there is no winner. + // + // `ad_metadata` The metadata for the winning ad. + // + // `winning_interest_group_owner` owner of the winning interest group. + // An opaque origin if there is no winner. + // + // `winning_interest_group_name` name of winning interest group. Empty if + // there is no winner. + // + // `bidder_report_url` URL to use for reporting result to the bidder. Empty if + // no report should be sent. + // + // `seller_report` URL to use for reporting result to the seller. Empty if no + // report should be sent. + // + // `errors` are various error messages to be used for debugging. These are too + // sensitive for the renderers to see. + using RunAuctionCallback = + base::OnceCallback<void(const GURL& render_url, + const std::string& ad_metadata, + const url::Origin& winning_interest_group_owner, + const std::string& winning_interest_group_name, + const GURL& bidder_report_url, + const GURL& seller_report_url, + const std::vector<std::string>& errors)>; + + // Delegate class to allow dependency injection in tests. Note that all + // objects this returns can crash and be restarted, so passing in raw pointers + // would be problematic. + class Delegate { + public: + // Returns the URLLoaderFactory of the frame running the auction. Used to + // load the seller worklet in the context of the parent frame, since unlike + // other worklet types, it has no first party opt-in, and it's not a + // cross-origin leak if the parent from knows its URL, since the parent + // frame provided the URL in the first place. + virtual network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() = 0; + + // Trusted URLLoaderFactory used to load bidder worklets. + virtual network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() = 0; + + // Returns the AuctionWorkletService. + virtual auction_worklet::mojom::AuctionWorkletService* + GetWorkletService() = 0; + }; + + explicit AuctionRunner(const AuctionRunner&) = delete; + AuctionRunner& operator=(const AuctionRunner&) = delete; + + // Runs an entire FLEDGE auction. + // + // Arguments: + // `delegate` must remain valid until the AuctionRunner is destroyed. + // + // `auction_config` is the configuration provided by client JavaScript in + // the renderer in order to initiate the auction. + // + // `bidders` includes definitions of the interest groups that are selected to + // participate in this auction (initially added by client JS in the renderer, + // but managed by the browser's interest group store), as well as some + // bidding history collected by the interest group store. The bidding + // worklets of these groups will be fetched and executed. `bidders` must not + // be empty. + // + // `browser_signals` signals from the browser about the auction that are the + // same for all worklets. + // + // `frame_origin` is the origin running the auction (not the top frame + // origin), used as the initiator in network requests. + static std::unique_ptr<AuctionRunner> CreateAndStart( + Delegate* delegate, + blink::mojom::AuctionAdConfigPtr auction_config, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + auction_worklet::mojom::BrowserSignalsPtr browser_signals, + const url::Origin& frame_origin, + RunAuctionCallback callback); + + ~AuctionRunner(); + + private: + struct BidState { + BidState(); + BidState(BidState&&); + ~BidState(); + + auction_worklet::mojom::BiddingInterestGroup* bidder = nullptr; + + // URLLoaderFactory proxy class configured only to load the URLs the bidder + // needs. + std::unique_ptr<AuctionURLLoaderFactoryProxy> url_loader_factory_; + + mojo::Remote<auction_worklet::mojom::BidderWorklet> bidder_worklet; + auction_worklet::mojom::BidderWorkletBidPtr bid_result; + // Points to the InterestGroupAd within `bidder` that won the auction. Only + // nullptr when `bid_result` is also nullptr. + blink::mojom::InterestGroupAd* bid_ad = nullptr; + + double seller_score = 0; + }; + + AuctionRunner( + Delegate* delegate, + blink::mojom::AuctionAdConfigPtr auction_config, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + auction_worklet::mojom::BrowserSignalsPtr browser_signals, + const url::Origin& frame_origin, + RunAuctionCallback callback); + + void StartBidding(); + void OnGenerateBidCrashed(BidState* state); + void OnGenerateBidComplete(BidState* state, + auction_worklet::mojom::BidderWorkletBidPtr bid, + const std::vector<std::string>& errors); + + // True if all bid results and the seller script load are complete. + bool ReadyToScore() const { return outstanding_bids_ == 0 && seller_loaded_; } + void OnSellerWorkletLoaded(bool load_result, + const std::vector<std::string>& errors); + + // Calls into the seller asynchronously to score each outstanding bid, in + // series. Once there are no outstanding bids, proceeds to selecting the + // winner and running the Worklets reporting methods. + void ScoreOne(); + void ScoreBid(const BidState* state); + // Callback from ScoreBid(). + void OnBidScored(double score, const std::vector<std::string>& errors); + + std::string AdRenderFingerprint(const BidState* state); + absl::optional<std::string> PerBuyerSignals(const BidState* state); + + // Completes the auction, invoking `callback_`. Consumer must be able to + // safely delete `this` when the callback is invoked. + void CompleteAuction(); + + // Sequence of asynchronous methods to call into the bidder/seller results to + // report a a win, Will ultimately invoke ReportSuccess(), which will delete + // the auction. + void ReportSellerResult(BidState* state); + void OnReportSellerResultComplete( + BidState* best_bid, + const absl::optional<std::string>& signals_for_winner, + const absl::optional<GURL>& seller_report_url, + const std::vector<std::string>& error_msgs); + void ReportBidWin(BidState* state); + void OnReportBidWinComplete(const BidState* best_bid, + const absl::optional<GURL>& bidder_report_url, + const std::vector<std::string>& error_msgs); + + // These complete the auction, invoking `callback_` and preventing any future + // calls into `this` by closing mojo pipes and disposing of weak pointers. The + // owner must be able to safely delete `this` when the callback is invoked. + void FailAuction(); + // Appends `error` to `errors_` before calling FailAuciton(). + void FailAuctionWithError(std::string error); + void ReportSuccess(const BidState* state); + + // Closes all open pipes, to avoid receiving any Mojo callbacks after + // completion. + void ClosePipes(); + + Delegate* const delegate_; + + // Configuration. + blink::mojom::AuctionAdConfigPtr auction_config_; + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders_; + auction_worklet::mojom::BrowserSignalsPtr browser_signals_; + const url::Origin frame_origin_; + RunAuctionCallback callback_; + + // State for the bidding phase. + int outstanding_bids_; // number of bids for which we're waiting on a fetch. + std::vector<BidState> bid_states_; // parallel to `bidders_`. + // The time the auction started. Use a single base time for all Worklets, to + // present a more consistent view of the universe. + const base::Time auction_start_time_ = base::Time::Now(); + + // URLLoaderFactory proxy class configured only to load the URL the seller + // needs. + std::unique_ptr<AuctionURLLoaderFactoryProxy> seller_url_loader_factory_; + + // State for the scoring phase. + mojo::Remote<auction_worklet::mojom::SellerWorklet> seller_worklet_; + + // This is true if the seller script has been loaded successfully --- if the + // load failed, the entire process is aborted since there is nothing useful + // that can be done. + bool seller_loaded_ = false; + size_t seller_considering_ = 0; + + // Seller script reportResult() results. + absl::optional<std::string> signals_for_winner_; + absl::optional<GURL> seller_report_url_; + + // Bidder script reportWin() results. + absl::optional<GURL> bidder_report_url_; + + // All errors reported by worklets thus far. + std::vector<std::string> errors_; + + base::WeakPtrFactory<AuctionRunner> weak_ptr_factory_{this}; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_INTEREST_GROUP_AUCTION_RUNNER_H_
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc new file mode 100644 index 0000000..3d912ca9 --- /dev/null +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -0,0 +1,1863 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/interest_group/auction_runner.h" + +#include <limits> +#include <vector> + +#include "base/callback_helpers.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "content/services/auction_worklet/auction_worklet_service_impl.h" +#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" +#include "content/services/auction_worklet/worklet_test_util.h" +#include "mojo/public/cpp/system/functions.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock-matchers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace { + +std::string MakeBidScript(const std::string& bid, + const std::string& render_url, + const url::Origin& interest_group_owner, + const std::string& interest_group_name, + bool has_signals, + const std::string& signal_key, + const std::string& signal_val) { + // TODO(morlovich): Use JsReplace. + constexpr char kBidScript[] = R"( + const bid = %s; + const renderUrl = "%s"; + const interestGroupOwner = "%s"; + const interestGroupName = "%s"; + const hasSignals = %s; + + function generateBid(interestGroup, auctionSignals, perBuyerSignals, + trustedBiddingSignals, browserSignals) { + var result = {ad: {bidKey: "data for " + bid, + groupName: interestGroupName}, + bid: bid, render: renderUrl}; + if (interestGroup.name !== interestGroupName) + throw new Error("wrong interestGroupName"); + if (interestGroup.owner !== interestGroupOwner) + throw new Error("wrong interestGroupOwner"); + if (interestGroup.ads.length != 1) + throw new Error("wrong interestGroup.ads length"); + if (interestGroup.ads[0].renderUrl != renderUrl) + throw new Error("wrong interestGroup.ads URL"); + if (perBuyerSignals.signalsFor !== interestGroupName) + throw new Error("wrong perBuyerSignals"); + if (!auctionSignals.isAuctionSignals) + throw new Error("wrong auctionSignals"); + if (hasSignals) { + if ('extra' in trustedBiddingSignals) + throw new Error("why extra?"); + if (trustedBiddingSignals["%s"] !== "%s") + throw new Error("wrong signals"); + } else if (trustedBiddingSignals !== null) { + throw new Error("Expected null trustedBiddingSignals"); + } + if (browserSignals.topWindowHostname !== 'publisher1.com') + throw new Error("wrong topWindowHostname"); + if (browserSignals.seller != 'https://adstuff.publisher1.com') + throw new Error("wrong seller"); + if (browserSignals.joinCount !== 3) + throw new Error("joinCount") + if (browserSignals.bidCount !== 5) + throw new Error("bidCount"); + if (browserSignals.prevWins.length !== 3) + throw new Error("prevWins"); + for (let i = 0; i < browserSignals.prevWins.length; ++i) { + if (!(browserSignals.prevWins[i] instanceof Array)) + throw new Error("prevWins entry not an array"); + if (typeof browserSignals.prevWins[i][0] != "number") + throw new Error("Not a Number in prevWin?"); + if (browserSignals.prevWins[i][1].winner !== -i) + throw new Error("prevWin MD not what passed in"); + } + return result; + } + + function reportWin(auctionSignals, perBuyerSignals, sellerSignals, + browserSignals) { + if (!auctionSignals.isAuctionSignals) + throw new Error("wrong auctionSignals"); + if (perBuyerSignals.signalsFor !== interestGroupName) + throw new Error("wrong perBuyerSignals"); + + // sellerSignals in these tests is just sellers' browserSignals, since + // that's what reportResult passes through. + if (sellerSignals.topWindowHostname !== 'publisher1.com') + throw new Error("wrong topWindowHostname"); + if (sellerSignals.interestGroupOwner !== interestGroupOwner) + throw new Error("wrong interestGroupOwner"); + if (sellerSignals.renderUrl !== renderUrl) + throw new Error("wrong renderUrl"); + if (sellerSignals.bid !== bid) + throw new Error("wrong bid"); + if (sellerSignals.desirability !== (bid * 2)) + throw new Error("wrong desirability"); + + if (browserSignals.topWindowHostname !== 'publisher1.com') + throw new Error("wrong browserSignals.topWindowHostname"); + if ("desirability" in browserSignals) + throw new Error("why is desirability here?"); + if (browserSignals.interestGroupName !== interestGroupName) + throw new Error("wrong browserSignals.interestGroupName"); + if (browserSignals.interestGroupOwner !== interestGroupOwner) + throw new Error("wrong browserSignals.interestGroupOwner"); + + if (browserSignals.renderUrl !== renderUrl) + throw new Error("wrong browserSignals.renderUrl"); + if (browserSignals.bid !== bid) + throw new Error("wrong browserSignals.bid"); + + sendReportTo("https://buyer-reporting.example.com"); + } + )"; + return base::StringPrintf( + kBidScript, bid.c_str(), render_url.c_str(), + interest_group_owner.Serialize().c_str(), interest_group_name.c_str(), + has_signals ? "true" : "false", signal_key.c_str(), signal_val.c_str()); +} + +// This can be appended to the standard script to override the function. +constexpr char kReportWinNoUrl[] = R"( + function reportWin(auctionSignals, perBuyerSignals, sellerSignals, + browserSignals) { + } +)"; + +constexpr char kCheckingAuctionScript[] = R"( + function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals, + browserSignals) { + if (adMetadata.bidKey !== ("data for " + bid)) { + throw new Error("wrong data for bid:" + + JSON.stringify(adMetadata) + "/" + bid); + } + if (auctionConfig.decisionLogicUrl + !== "https://adstuff.publisher1.com/auction.js") { + throw new Error("wrong auctionConfig"); + } + if (auctionConfig.perBuyerSignals['adplatform.com'].signalsFor + !== 'Ad Platform') { + throw new Error("Wrong perBuyerSignals in auctionConfig"); + } + if (!auctionConfig.sellerSignals.isSellerSignals) + throw new Error("Wrong sellerSignals"); + if (browserSignals.topWindowHostname !== 'publisher1.com') + throw new Error("wrong topWindowHostname"); + if ("joinCount" in browserSignals) + throw new Error("wrong kind of browser signals"); + if (browserSignals.adRenderFingerprint !== "#####") + throw new Error("wrong adRenderFingerprint"); + if (typeof browserSignals.biddingDurationMsec !== "number") + throw new Error("biddingDurationMsec is not a number. huh"); + if (browserSignals.biddingDurationMsec < 0) + throw new Error("biddingDurationMsec should be non-negative."); + + return bid * 2; + } +)"; + +constexpr char kReportResultScript[] = R"( + function reportResult(auctionConfig, browserSignals) { + if (auctionConfig.decisionLogicUrl + !== "https://adstuff.publisher1.com/auction.js") { + throw new Error("wrong auctionConfig"); + } + if (browserSignals.topWindowHostname !== 'publisher1.com') + throw new Error("wrong topWindowHostname"); + sendReportTo("https://reporting.example.com"); + return browserSignals; + } +)"; + +constexpr char kReportResultScriptNoUrl[] = R"( + function reportResult(auctionConfig, browserSignals) { + return browserSignals; + } +)"; + +std::string MakeAuctionScript() { + return std::string(kCheckingAuctionScript) + kReportResultScript; +} + +std::string MakeAuctionScriptNoReportUrl() { + return std::string(kCheckingAuctionScript) + kReportResultScriptNoUrl; +} + +const char kAuctionScriptRejects2[] = R"( + function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { + if (bid === 2) + return -1; + return bid + 1; + } +)"; + +std::string MakeAuctionScriptReject2() { + return std::string(kAuctionScriptRejects2) + kReportResultScript; +} + +// BidderWorklet that holds onto passed in callbacks, to let the test fixture +// invoke them. +class MockBidderWorklet : public auction_worklet::mojom::BidderWorklet { + public: + explicit MockBidderWorklet( + mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet> + pending_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + auction_worklet::mojom::AuctionWorkletService:: + LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback) + : load_bidder_worklet_and_generate_bid_callback_( + std::move(load_bidder_worklet_and_generate_bid_callback)), + url_loader_factory_(std::move(pending_url_loader_factory)), + receiver_(this, std::move(pending_receiver)) {} + + MockBidderWorklet(const MockBidderWorklet&) = delete; + const MockBidderWorklet& operator=(const MockBidderWorklet&) = delete; + + ~MockBidderWorklet() override = default; + + // auction_worklet::mojom::BidderWorklet implementation: + void ReportWin(const std::string& seller_signals_json, + const GURL& browser_signal_render_url, + const std::string& browser_signal_ad_render_fingerprint, + double browser_signal_bid, + ReportWinCallback report_win_callback) override { + report_win_callback_ = std::move(report_win_callback); + if (report_win_run_loop_) + report_win_run_loop_->Quit(); + } + + void CompleteLoadingAndBid(double bid, + const GURL& render_url, + base::TimeDelta duration = base::TimeDelta()) { + DCHECK(load_bidder_worklet_and_generate_bid_callback_); + std::move(load_bidder_worklet_and_generate_bid_callback_) + .Run(auction_worklet::mojom::BidderWorkletBid::New( + "ad", bid, render_url, duration), + std::vector<std::string>() /* errors */); + } + + void CompleteLoadingWithoutBid() { + DCHECK(load_bidder_worklet_and_generate_bid_callback_); + std::move(load_bidder_worklet_and_generate_bid_callback_) + .Run(nullptr /* bid */, std::vector<std::string>() /* errors */); + } + + // Returns the LoadBidderWorkletAndGenerateBidCallback for a worklet. Needed + // for cases when the BidderWorklet is destroyed (to close its pipe) before + // the AuctionWorkletService is destroyed, since Mojo DCHECKs if a callback is + // destroyed when the pipe its over is still live. + // + // TODO(mmenke): To better simulate real crashes, give worklets their own + // AuctionWorkletService pipes, and remove this method. + auction_worklet::mojom::AuctionWorkletService:: + LoadBidderWorkletAndGenerateBidCallback + TakeLoadCallback() { + return std::move(load_bidder_worklet_and_generate_bid_callback_); + } + + void WaitForReportWin() { + DCHECK(!load_bidder_worklet_and_generate_bid_callback_); + DCHECK(!report_win_run_loop_); + if (!report_win_callback_) { + report_win_run_loop_ = std::make_unique<base::RunLoop>(); + report_win_run_loop_->Run(); + report_win_run_loop_.reset(); + DCHECK(report_win_callback_); + } + } + + void InvokeReportWinCallback( + absl::optional<GURL> report_url = absl::nullopt) { + DCHECK(report_win_callback_); + std::move(report_win_callback_) + .Run(report_url, std::vector<std::string>() /* errors */); + } + + mojo::Remote<network::mojom::URLLoaderFactory>& url_loader_factory() { + return url_loader_factory_; + } + + private: + auction_worklet::mojom::AuctionWorkletService:: + LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback_; + + std::unique_ptr<base::RunLoop> report_win_run_loop_; + ReportWinCallback report_win_callback_; + + mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_; + + // Receiver is last so that destroying `this` while there's a pending callback + // over the pipe will not DCHECK. + mojo::Receiver<auction_worklet::mojom::BidderWorklet> receiver_; +}; + +// SellerWorklet that holds onto passed in callbacks, to let the test fixture +// invoke them. +class MockSellerWorklet : public auction_worklet::mojom::SellerWorklet { + public: + // Subset of parameters passed to SellerWorklet's ScoreAd method. + struct ScoreAdParams { + double bid; + url::Origin interest_group_owner; + }; + + explicit MockSellerWorklet( + mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet> + pending_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + auction_worklet::mojom::AuctionWorkletService::LoadSellerWorkletCallback + load_worklet_callback) + : load_worklet_callback_(std::move(load_worklet_callback)), + url_loader_factory_(std::move(pending_url_loader_factory)), + receiver_(this, std::move(pending_receiver)) {} + + MockSellerWorklet(const MockSellerWorklet&) = delete; + const MockSellerWorklet& operator=(const MockSellerWorklet&) = delete; + + ~MockSellerWorklet() override = default; + + // auction_worklet::mojom::SellerWorklet implementation: + + void ScoreAd(const std::string& ad_metadata_json, + double bid, + blink::mojom::AuctionAdConfigPtr auction_config, + const url::Origin& browser_signal_top_window_origin, + const url::Origin& browser_signal_interest_group_owner, + const std::string& browser_signal_ad_render_fingerprint, + uint32_t browser_signal_bidding_duration_msecs, + ScoreAdCallback score_ad_callback) override { + score_ad_callback_ = std::move(score_ad_callback); + score_ad_params_ = std::make_unique<ScoreAdParams>(); + score_ad_params_->bid = bid; + score_ad_params_->interest_group_owner = + browser_signal_interest_group_owner; + if (score_ad_run_loop_) + score_ad_run_loop_->Quit(); + } + + void ReportResult(blink::mojom::AuctionAdConfigPtr auction_config, + const url::Origin& browser_signal_top_window_origin, + const url::Origin& browser_signal_interest_group_owner, + const GURL& browser_signal_render_url, + const std::string& browser_signal_ad_render_fingerprint, + double browser_signal_bid, + double browser_signal_desirability, + ReportResultCallback report_result_callback) override { + report_result_callback_ = std::move(report_result_callback); + if (report_result_run_loop_) + report_result_run_loop_->Quit(); + } + + // Informs the consumer that the seller worklet has successfully loaded. + void CompleteLoading() { + DCHECK(load_worklet_callback_); + std::move(load_worklet_callback_) + .Run(true /* success */, std::vector<std::string>() /* errors */); + } + + // Waits until ScoreAd() has been invoked, if it hasn't been already. + std::unique_ptr<ScoreAdParams> WaitForScoreAd() { + DCHECK(!score_ad_run_loop_); + DCHECK(!load_worklet_callback_); + if (!score_ad_params_) { + score_ad_run_loop_ = std::make_unique<base::RunLoop>(); + score_ad_run_loop_->Run(); + score_ad_run_loop_.reset(); + DCHECK(score_ad_params_); + } + return std::move(score_ad_params_); + } + + // Invokes the ScoreAdCallback for the most recent ScoreAd() call with the + // provided score. WaitForScoreAd() must have been invoked first. + void InvokeScoreAdCallback(double score) { + DCHECK(score_ad_callback_); + DCHECK(!score_ad_params_); + std::move(score_ad_callback_) + .Run(score, std::vector<std::string>() /* errors */); + } + + void WaitForReportResult() { + DCHECK(!report_result_run_loop_); + DCHECK(!load_worklet_callback_); + if (!report_result_callback_) { + report_result_run_loop_ = std::make_unique<base::RunLoop>(); + report_result_run_loop_->Run(); + report_result_run_loop_.reset(); + DCHECK(report_result_callback_); + } + } + + // Invokes the ReportResultCallback for the most recent ScoreAd() call with + // the provided score. WaitForReportResult() must have been invoked first. + void InvokeReportResultCallback( + absl::optional<GURL> report_url = absl::nullopt) { + DCHECK(report_result_callback_); + std::move(report_result_callback_) + .Run(absl::nullopt /* signals_for_winner */, std::move(report_url), + std::vector<std::string>() /* errors */); + } + + mojo::Remote<network::mojom::URLLoaderFactory>& url_loader_factory() { + return url_loader_factory_; + } + + private: + auction_worklet::mojom::AuctionWorkletService::LoadSellerWorkletCallback + load_worklet_callback_; + + std::unique_ptr<base::RunLoop> score_ad_run_loop_; + std::unique_ptr<ScoreAdParams> score_ad_params_; + ScoreAdCallback score_ad_callback_; + + std::unique_ptr<base::RunLoop> report_result_run_loop_; + ReportResultCallback report_result_callback_; + + mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_; + + // Receiver is last so that destroying `this` while there's a pending callback + // over the pipe will not DCHECK. + mojo::Receiver<auction_worklet::mojom::SellerWorklet> receiver_; +}; + +// AuctionWorkletService that creates MockBidderWorklets and MockSellerWorklets +// to hold onto passed in PendingReceivers and Callbacks. +class MockAuctionWorkletService + : public auction_worklet::mojom::AuctionWorkletService { + public: + explicit MockAuctionWorkletService( + mojo::PendingReceiver<auction_worklet::mojom::AuctionWorkletService> + pending_receiver) + : receiver_(this, std::move(pending_receiver)) {} + + ~MockAuctionWorkletService() override = default; + + // auction_worklet::mojom::AuctionWorkletService implementation: + + void LoadBidderWorkletAndGenerateBid( + mojo::PendingReceiver<auction_worklet::mojom::BidderWorklet> + bidder_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + auction_worklet::mojom::BiddingInterestGroupPtr bidding_interest_group, + const absl::optional<std::string>& auction_signals_json, + const absl::optional<std::string>& per_buyer_signals_json, + const url::Origin& top_window_origin, + const url::Origin& seller_origin, + base::Time auction_start_time, + LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback) override { + InterestGroupId interest_group_id(bidding_interest_group->group->owner, + bidding_interest_group->group->name); + EXPECT_EQ(0u, bidder_worklets_.count(interest_group_id)); + bidder_worklets_.emplace(std::make_pair( + interest_group_id, + std::make_unique<MockBidderWorklet>( + std::move(bidder_worklet_receiver), + std::move(pending_url_loader_factory), + std::move(load_bidder_worklet_and_generate_bid_callback)))); + + ASSERT_GT(waiting_for_num_bidders_, 0); + --waiting_for_num_bidders_; + MaybeQuitRunLoop(); + } + + void LoadSellerWorklet( + mojo::PendingReceiver<auction_worklet::mojom::SellerWorklet> + seller_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + const GURL& script_source_url, + LoadSellerWorkletCallback load_seller_worklet_callback) override { + DCHECK(!seller_worklet_); + + seller_worklet_ = std::make_unique<MockSellerWorklet>( + std::move(seller_worklet_receiver), + std::move(pending_url_loader_factory), + std::move(load_seller_worklet_callback)); + + ASSERT_TRUE(waiting_on_seller_); + waiting_on_seller_ = false; + MaybeQuitRunLoop(); + } + + // Waits for a SellerWorklet and `num_bidders` bidder worklets to be created. + void WaitForWorklets(int num_bidders) { + waiting_on_seller_ = true; + waiting_for_num_bidders_ = num_bidders; + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); + run_loop_.reset(); + } + + // Returns the MockBidderWorklet created for the specified interest group + // origin and name, if there is one. + std::unique_ptr<MockBidderWorklet> TakeBidderWorklet( + const url::Origin& interest_group_owner_origin, + const std::string& interest_group_name) { + InterestGroupId interest_group_id(interest_group_owner_origin, + interest_group_name); + auto it = bidder_worklets_.find(interest_group_id); + if (it == bidder_worklets_.end()) + return nullptr; + std::unique_ptr<MockBidderWorklet> out = std::move(it->second); + bidder_worklets_.erase(it); + return out; + } + + // Returns the MockSellerWorklet, if one has been created. + std::unique_ptr<MockSellerWorklet> TakeSellerWorklet() { + return std::move(seller_worklet_); + } + + void Flush() { receiver_.FlushForTesting(); } + + private: + void MaybeQuitRunLoop() { + if (!waiting_on_seller_ && waiting_for_num_bidders_ == 0) + run_loop_->Quit(); + } + + // An interest group is uniquely identified by its owner's origin and name. + using InterestGroupId = std::pair<url::Origin, std::string>; + + std::map<InterestGroupId, std::unique_ptr<MockBidderWorklet>> + bidder_worklets_; + + std::unique_ptr<MockSellerWorklet> seller_worklet_; + + std::unique_ptr<base::RunLoop> run_loop_; + bool waiting_on_seller_ = false; + int waiting_for_num_bidders_ = 0; + + // Receiver is last so that destroying `this` while there's a pending callback + // over the pipe will not DCHECK. + mojo::Receiver<auction_worklet::mojom::AuctionWorkletService> receiver_; +}; + +class AuctionRunnerTest : public testing::Test, public AuctionRunner::Delegate { + protected: + // Output of the RunAuctionCallback passed to AuctionRunner::CreateAndStart(). + struct Result { + GURL ad_url; + std::string ad_metadata; + url::Origin interest_group_owner; + std::string interest_group_name; + GURL bidder_report_url; + GURL seller_report_url; + std::vector<std::string> errors; + }; + + AuctionRunnerTest() + : auction_worklet_service_( + auction_worklet_service_remote_.BindNewPipeAndPassReceiver()) { + mojo::SetDefaultProcessErrorHandler(base::BindRepeating( + &AuctionRunnerTest::OnBadMessage, base::Unretained(this))); + } + + ~AuctionRunnerTest() override { + // Any bad message should have been inspected and cleared before the end of + // the test. + EXPECT_EQ(std::string(), bad_message_); + mojo::SetDefaultProcessErrorHandler(base::NullCallback()); + } + + void OnBadMessage(const std::string& reason) { + // No test expects multiple bad messages at a time + EXPECT_EQ(std::string(), bad_message_); + // Empty bad messages aren't expected. This check allows an empty + // `bad_message_` field to mean no bad message, avoiding using an optional, + // which has less helpful output on EXPECT failures. + EXPECT_FALSE(reason.empty()); + + bad_message_ = reason; + } + + // Gets and clear most recent bad Mojo message. + std::string TakeBadMessage() { return std::move(bad_message_); } + + // Starts an auction without waiting for it to complete. Useful when using + // MockAuctionWorkletService. + void StartAuction( + const GURL& seller_decision_logic_url, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + const std::string& auction_signals_json, + auction_worklet::mojom::BrowserSignalsPtr browser_signals) { + auction_complete_ = false; + + blink::mojom::AuctionAdConfigPtr auction_config = + blink::mojom::AuctionAdConfig::New(); + auction_config->seller = url::Origin::Create(seller_decision_logic_url); + auction_config->decision_logic_url = seller_decision_logic_url; + auction_config->interest_group_buyers = + blink::mojom::InterestGroupBuyers::NewAllBuyers( + blink::mojom::AllBuyers::New()); + auction_config->auction_signals = auction_signals_json; + auction_config->seller_signals = R"({"isSellerSignals": true})"; + + base::flat_map<url::Origin, std::string> per_buyer_signals; + per_buyer_signals[kBidder1] = R"({"signalsFor": ")" + kBidder1Name + "\"}"; + per_buyer_signals[kBidder2] = R"({"signalsFor": ")" + kBidder2Name + "\"}"; + auction_config->per_buyer_signals = std::move(per_buyer_signals); + + auction_run_loop_ = std::make_unique<base::RunLoop>(); + Result result; + auction_runner_ = AuctionRunner::CreateAndStart( + this, std::move(auction_config), std::move(bidders), + std::move(browser_signals), frame_origin_, + base::BindOnce(&AuctionRunnerTest::OnAuctionComplete, + base::Unretained(this))); + } + + Result RunAuctionAndWait( + const GURL& seller_decision_logic_url, + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders, + const std::string& auction_signals_json, + auction_worklet::mojom::BrowserSignalsPtr browser_signals) { + StartAuction(seller_decision_logic_url, std::move(bidders), + auction_signals_json, std::move(browser_signals)); + auction_run_loop_->Run(); + return result_; + } + + void OnAuctionComplete(const GURL& ad_url, + const std::string& ad_metadata, + const url::Origin& interest_group_owner, + const std::string& interest_group_name, + const GURL& bidder_report_url, + const GURL& seller_report_url, + const std::vector<std::string>& errors) { + auction_complete_ = true; + result_.ad_url = ad_url; + result_.ad_metadata = ad_metadata; + result_.interest_group_owner = interest_group_owner; + result_.interest_group_name = interest_group_name; + result_.bidder_report_url = bidder_report_url; + result_.seller_report_url = seller_report_url; + result_.errors = errors; + auction_run_loop_->Quit(); + } + + auction_worklet::mojom::BiddingInterestGroupPtr MakeInterestGroup( + const url::Origin& owner, + const std::string& name, + const GURL& bidding_url, + const absl::optional<GURL>& trusted_bidding_signals_url, + const std::vector<std::string>& trusted_bidding_signals_keys, + const GURL& ad_url) { + std::vector<blink::mojom::InterestGroupAdPtr> ads; + // Give only kBidder1 an InterestGroupAd ad with non-empty metadata, to + // better test the `ad_metadata` output. + if (owner == kBidder1) { + ads.push_back( + blink::mojom::InterestGroupAd::New(ad_url, R"({"ads": true})")); + } else { + ads.push_back(blink::mojom::InterestGroupAd::New(ad_url, absl::nullopt)); + } + + std::vector<auction_worklet::mojom::PreviousWinPtr> previous_wins; + previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( + base::Time::Now(), R"({"winner": 0})")); + previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( + base::Time::Now(), R"({"winner": -1})")); + previous_wins.push_back(auction_worklet::mojom::PreviousWin::New( + base::Time::Now(), R"({"winner": -2})")); + + return auction_worklet::mojom::BiddingInterestGroup::New( + blink::mojom::InterestGroup::New( + base::Time::Max(), owner, name, bidding_url, + GURL() /* update_url */, trusted_bidding_signals_url, + trusted_bidding_signals_keys, absl::nullopt, std::move(ads)), + auction_worklet::mojom::BiddingBrowserSignals::New( + 3, 5, std::move(previous_wins))); + } + + void StartStandardAuction() { + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders; + bidders.push_back(MakeInterestGroup(kBidder1, kBidder1Name, kBidder1Url, + kTrustedSignalsUrl, {"k1", "k2"}, + GURL("https://ad1.com"))); + bidders.push_back(MakeInterestGroup(kBidder2, kBidder2Name, kBidder2Url, + kTrustedSignalsUrl, {"l1", "l2"}, + GURL("https://ad2.com"))); + + StartAuction(kSellerUrl, std::move(bidders), + R"({"isAuctionSignals": true})", /* auction_signals_json */ + auction_worklet::mojom::BrowserSignals::New( + url::Origin::Create(GURL("https://publisher1.com")), + url::Origin::Create(kSellerUrl))); + } + + Result RunStandardAuction() { + StartStandardAuction(); + auction_run_loop_->Run(); + return result_; + } + + // Starts the standard auction with the mock worklet service, and waits for + // the service to receive the worklet construction calls. + void StartStandardAuctionWithMockService() { + use_mock_service_ = true; + StartStandardAuction(); + mock_worklet_service_->WaitForWorklets(2 /* num_bidders */); + } + + // AuctionRunner::Delegate implementation: + network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override { + return &url_loader_factory_; + } + network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() override { + return &url_loader_factory_; + } + auction_worklet::mojom::AuctionWorkletService* GetWorkletService() override { + if (use_mock_service_) { + if (!mock_worklet_service_) { + mock_worklet_service_remote_.reset(); + mock_worklet_service_ = std::make_unique<MockAuctionWorkletService>( + mock_worklet_service_remote_.BindNewPipeAndPassReceiver()); + } + return mock_worklet_service_remote_.get(); + } + return auction_worklet_service_remote_.get(); + } + + const url::Origin frame_origin_ = + url::Origin::Create(GURL("https://frame.origin.test")); + const GURL kSellerUrl{"https://adstuff.publisher1.com/auction.js"}; + const GURL kBidder1Url{"https://adplatform.com/offers.js"}; + const url::Origin kBidder1 = + url::Origin::Create(GURL("https://adplatform.com")); + const std::string kBidder1Name{"Ad Platform"}; + const GURL kBidder2Url{"https://anotheradthing.com/bids.js"}; + const url::Origin kBidder2 = + url::Origin::Create(GURL("https://anotheradthing.com")); + const std::string kBidder2Name{"Another Ad Thing"}; + + const GURL kTrustedSignalsUrl{"https://trustedsignaller.org/signals"}; + + base::test::TaskEnvironment task_environment_; + + bool use_mock_service_ = false; + + // RunLoop that's quit on auction completion. + std::unique_ptr<base::RunLoop> auction_run_loop_; + // True if the most recently started auction has completed. + bool auction_complete_ = false; + // Result of the most recent auction. + Result result_; + + network::TestURLLoaderFactory url_loader_factory_; + mojo::Remote<auction_worklet::mojom::AuctionWorkletService> + mock_worklet_service_remote_; + std::unique_ptr<MockAuctionWorkletService> mock_worklet_service_; + + mojo::Remote<auction_worklet::mojom::AuctionWorkletService> + auction_worklet_service_remote_; + auction_worklet::AuctionWorkletServiceImpl auction_worklet_service_; + + std::unique_ptr<AuctionRunner> auction_runner_; + // This should be inspected using TakeBadMessage(), which also clears it. + std::string bad_message_; +}; + +// An auction with two successful bids. +TEST_F(AuctionRunnerTest, Basic) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT(res.errors, testing::ElementsAre()); +} + +// An auction where one bid is successful, another's script 404s. +TEST_F(AuctionRunnerTest, OneBidOne404) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + url_loader_factory_.AddResponse(kBidder2Url.spec(), "", net::HTTP_NOT_FOUND); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", + res.ad_metadata); + EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Ad Platform", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT( + res.errors, + testing::ElementsAre("Failed to load https://anotheradthing.com/bids.js " + "HTTP status = 404 Not Found.")); +} + +// An auction where one bid is successful, another's script does not provide a +// bidding function. +TEST_F(AuctionRunnerTest, OneBidOneNotMade) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + + // The auction script doesn't make any bids. + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder2Url, + MakeAuctionScript()); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", + res.ad_metadata); + EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Ad Platform", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT(res.errors, + testing::ElementsAre("https://anotheradthing.com/bids.js " + "`generateBid` is not a function.")); +} + +// An auction where no bidding scripts load successfully. +TEST_F(AuctionRunnerTest, NoBids) { + url_loader_factory_.AddResponse(kBidder1Url.spec(), "", net::HTTP_NOT_FOUND); + url_loader_factory_.AddResponse(kBidder2Url.spec(), "", net::HTTP_NOT_FOUND); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2":"b", "extra":"c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra":"c"})"); + + Result res = RunStandardAuction(); + EXPECT_TRUE(res.ad_url.is_empty()); + EXPECT_TRUE(res.ad_metadata.empty()); + EXPECT_TRUE(res.interest_group_owner.opaque()); + EXPECT_EQ("", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + EXPECT_THAT( + res.errors, + testing::ElementsAre("Failed to load https://adplatform.com/offers.js " + "HTTP status = 404 Not Found.", + "Failed to load https://anotheradthing.com/bids.js " + "HTTP status = 404 Not Found.")); +} + +// An auction where none of the bidding scripts has a valid bidding function. +TEST_F(AuctionRunnerTest, NoBidMadeByScript) { + // MakeAuctionScript() is a valid script that doesn't have a bidding function. + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url, + MakeAuctionScript()); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder2Url, + MakeAuctionScript()); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2":"b", "extra":"c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra":"c"})"); + + Result res = RunStandardAuction(); + EXPECT_TRUE(res.ad_url.is_empty()); + EXPECT_TRUE(res.ad_metadata.empty()); + EXPECT_TRUE(res.interest_group_owner.opaque()); + EXPECT_EQ("", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + EXPECT_THAT( + res.errors, + testing::ElementsAre( + "https://adplatform.com/offers.js `generateBid` is not a function.", + "https://anotheradthing.com/bids.js `generateBid` is not a " + "function.")); +} + +// An auction where the seller script doesn't have a scoring function. +TEST_F(AuctionRunnerTest, SellerRejectsAll) { + std::string bid_script1 = + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a"); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url, + bid_script1); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b")); + + // No seller scoring function in a bid script. + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + bid_script1); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2":"b", "extra":"c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra":"c"})"); + + Result res = RunStandardAuction(); + EXPECT_TRUE(res.ad_url.is_empty()); + EXPECT_TRUE(res.ad_metadata.empty()); + EXPECT_TRUE(res.interest_group_owner.opaque()); + EXPECT_EQ("", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + EXPECT_THAT(res.errors, + testing::ElementsAre("https://adstuff.publisher1.com/auction.js " + "`scoreAd` is not a function.", + "https://adstuff.publisher1.com/auction.js " + "`scoreAd` is not a function.")); +} + +// An auction where seller rejects one bid when scoring. +TEST_F(AuctionRunnerTest, SellerRejectsOne) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScriptReject2()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", + res.ad_metadata); + EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Ad Platform", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); +} + +// An auction where the seller script fails to load. +TEST_F(AuctionRunnerTest, NoSellerScript) { + // Tests to make sure that if seller script fails the other fetches are + // cancelled, too. + url_loader_factory_.AddResponse(kSellerUrl.spec(), "", net::HTTP_NOT_FOUND); + Result res = RunStandardAuction(); + EXPECT_TRUE(res.ad_url.is_empty()); + EXPECT_TRUE(res.ad_metadata.empty()); + EXPECT_TRUE(res.interest_group_owner.opaque()); + EXPECT_EQ("", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + + EXPECT_EQ(0, url_loader_factory_.NumPending()); + EXPECT_THAT(res.errors, + testing::ElementsAre( + "Failed to load https://adstuff.publisher1.com/auction.js " + "HTTP status = 404 Not Found.")); +} + +// An auction where bidders don't requested trusted bidding signals. +TEST_F(AuctionRunnerTest, NoTrustedBiddingSignals) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + false /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + false /* has_signals */, "l2", "b")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders; + bidders.push_back(MakeInterestGroup(kBidder1, kBidder1Name, kBidder1Url, + absl::nullopt, {"k1", "k2"}, + GURL("https://ad1.com"))); + bidders.push_back(MakeInterestGroup(kBidder2, kBidder2Name, kBidder2Url, + absl::nullopt, {"l1", "l2"}, + GURL("https://ad2.com"))); + + Result res = RunAuctionAndWait( + kSellerUrl, std::move(bidders), + R"({"isAuctionSignals": true})", /* auction_signals_json */ + auction_worklet::mojom::BrowserSignals::New( + url::Origin::Create(GURL("https://publisher1.com")), + url::Origin::Create(kSellerUrl))); + + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT(res.errors, testing::ElementsAre()); +} + +// An auction where trusted bidding signals are requested, but the fetch 404s. +TEST_F(AuctionRunnerTest, TrustedBiddingSignals404) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + false /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + false /* has_signals */, "l2", "b")); + url_loader_factory_.AddResponse( + kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2", "", + net::HTTP_NOT_FOUND); + url_loader_factory_.AddResponse( + kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2", "", + net::HTTP_NOT_FOUND); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT(res.errors, + testing::ElementsAre("Failed to load " + "https://trustedsignaller.org/" + "signals?hostname=publisher1.com&keys=k1,k2 " + "HTTP status = 404 Not Found.", + "Failed to load " + "https://trustedsignaller.org/" + "signals?hostname=publisher1.com&keys=l1,l2 " + "HTTP status = 404 Not Found.")); +} + +// A successful auction where seller reporting worklet doesn't set a URL. +TEST_F(AuctionRunnerTest, NoReportResultUrl) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a")); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScriptNoReportUrl()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_EQ("https://buyer-reporting.example.com/", + res.bidder_report_url.spec()); + EXPECT_THAT(res.errors, testing::ElementsAre()); +} + +// A successful auction where bidder reporting worklet doesn't set a URL. +TEST_F(AuctionRunnerTest, NoReportWinUrl) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a") + + kReportWinNoUrl); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b") + + kReportWinNoUrl); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScript()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_EQ("https://reporting.example.com/", res.seller_report_url.spec()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + EXPECT_THAT(res.errors, testing::ElementsAre()); +} + +// A successful auction where neither reporting worklets sets a URL. +TEST_F(AuctionRunnerTest, NeitherReportUrl) { + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, + true /* has_signals */, "k1", "a") + + kReportWinNoUrl); + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder2Url, + MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, + true /* has_signals */, "l2", "b") + + kReportWinNoUrl); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + MakeAuctionScriptNoReportUrl()); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), + R"({"k1":"a", "k2": "b", "extra": "c"})"); + auction_worklet::AddJsonResponse( + &url_loader_factory_, + GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), + R"({"l1":"a", "l2": "b", "extra": "c"})"); + + Result res = RunStandardAuction(); + EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", res.ad_metadata); + EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); + EXPECT_EQ("Another Ad Thing", res.interest_group_name); + EXPECT_TRUE(res.seller_report_url.is_empty()); + EXPECT_TRUE(res.bidder_report_url.is_empty()); + EXPECT_THAT(res.errors, testing::ElementsAre()); +} + +TEST_F(AuctionRunnerTest, AllBiddersCrashBeforeBidding) { + for (bool seller_worklet_loads_first : {false, true}) { + SCOPED_TRACE(seller_worklet_loads_first); + + StartStandardAuctionWithMockService(); + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + if (seller_worklet_loads_first) { + seller_worklet->CompleteLoading(); + mock_worklet_service_->Flush(); + } + EXPECT_FALSE(auction_complete_); + + // Have to keep the callbacks around, since the AuctionWorkletService is + // still live. Closing it here causes more issues than its worth (seller + // worklet can't complete loading if it hasn't already). In production, + // there would be multiple service processes in this case, with different + // pipes. + auto bidder1_callback = bidder1_worklet->TakeLoadCallback(); + auto bidder2_callback = bidder2_worklet->TakeLoadCallback(); + bidder1_worklet.reset(); + bidder2_worklet.reset(); + + base::RunLoop().RunUntilIdle(); + // The auction isn't failed until the seller worklet has completed loading. + if (!seller_worklet_loads_first) + seller_worklet->CompleteLoading(); + + auction_run_loop_->Run(); + + EXPECT_FALSE(result_.ad_url.is_valid()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT( + result_.errors, + testing::UnorderedElementsAre( + base::StringPrintf("%s crashed while trying to run generateBid().", + kBidder1Url.spec().c_str()), + base::StringPrintf("%s crashed while trying to run generateBid().", + kBidder2Url.spec().c_str()))); + + // Reset the service, so callbacks can be destroyed without DCHECKing. + mock_worklet_service_.reset(); + } +} + +// Test the case a single bidder worklet crashes before bidding. The auction +// should continue, without that bidder's bid. +TEST_F(AuctionRunnerTest, BidderCrashBeforeBidding) { + for (bool other_bidder_finishes_first : {false, true}) { + SCOPED_TRACE(other_bidder_finishes_first); + for (bool seller_worklet_loads_first : {false, true}) { + SCOPED_TRACE(seller_worklet_loads_first); + StartStandardAuctionWithMockService(); + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + ASSERT_FALSE(auction_complete_); + if (seller_worklet_loads_first) + seller_worklet->CompleteLoading(); + if (other_bidder_finishes_first) { + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, + GURL("https://ad2.com/")); + } + mock_worklet_service_->Flush(); + + ASSERT_FALSE(auction_complete_); + + // Close Bidder1's pipe, keeping its callback alive to avoid a DCHECK. + auto bidder1_callback = bidder1_worklet->TakeLoadCallback(); + bidder1_worklet.reset(); + // Can't flush the closed pipe without reaching into AuctionRunner, so use + // RunUntilIdle() instead. + base::RunLoop().RunUntilIdle(); + + if (!seller_worklet_loads_first) + seller_worklet->CompleteLoading(); + if (!other_bidder_finishes_first) { + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, + GURL("https://ad2.com/")); + } + mock_worklet_service_->Flush(); + + // The auction should be scored without waiting on the crashed kBidder1. + auto score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder2, score_ad_params->interest_group_owner); + EXPECT_EQ(7, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(11); + + // Finish the auction. + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(); + bidder2_worklet->WaitForReportWin(); + bidder2_worklet->InvokeReportWinCallback(); + + // Bidder2 won, Bidder1 crashed. + auction_run_loop_->Run(); + EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_url); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", result_.ad_metadata); + EXPECT_EQ(kBidder2, result_.interest_group_owner); + EXPECT_EQ(kBidder2Name, result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, + testing::ElementsAre(base::StringPrintf( + "%s crashed while trying to run generateBid().", + kBidder1Url.spec().c_str()))); + + // Reset the service, so `bidder1_callback` can be destroyed without + // DCHECKing. + mock_worklet_service_.reset(); + } + } +} + +// If a losing bidder crashes while scoring, the auction should succeed. +TEST_F(AuctionRunnerTest, LosingBidderCrashWhileScoring) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad2.com/")); + + // Bidder1 crashes while the seller scores its bid. + auto score_ad_params = seller_worklet->WaitForScoreAd(); + bidder1_worklet.reset(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + // Score Bidder2's bid. + score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder2, score_ad_params->interest_group_owner); + EXPECT_EQ(7, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(11 /* score */); + + // Finish the auction. + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(); + bidder2_worklet->WaitForReportWin(); + bidder2_worklet->InvokeReportWinCallback(); + auction_run_loop_->Run(); + + // Bidder2 won. + EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_url); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", result_.ad_metadata); + EXPECT_EQ(kBidder2, result_.interest_group_owner); + EXPECT_EQ(kBidder2Name, result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + // Since Bidder1 crashed after bidding, don't report anything. + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// If the winning bidder crashes while scoring, the auction should fail. +TEST_F(AuctionRunnerTest, WinningBidderCrashWhileScoring) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + bidder1_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad2.com/")); + + // Bidder1 crashes while scoring its bid. + auto score_ad_params = seller_worklet->WaitForScoreAd(); + bidder1_worklet.reset(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(7, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(11 /* score */); + + // Score Bidder2's bid. + score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder2, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + // Finish the auction. + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(); + // AuctionRunner discovered Bidder1 crashed before calling its ReportWin + // method. + auction_run_loop_->Run(); + + // No bidder won, Bidder1 crashed. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, + testing::ElementsAre(base::StringPrintf( + "%s crashed while idle.", kBidder1Url.spec().c_str()))); +} + +// If the winning bidder crashes while coming up with the reporting URL, the +// auction should fail. +TEST_F(AuctionRunnerTest, WinningBidderCrashWhileReporting) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + bidder1_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad2.com/")); + + // Bidder1 crashes while scoring its bid. + auto score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(7, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(11 /* score */); + + // Score Bidder2's bid. + score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder2, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(); + bidder1_worklet->WaitForReportWin(); + bidder1_worklet.reset(); + auction_run_loop_->Run(); + + // No bidder won, Bidder1 crashed. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( + "%s crashed while trying to run reportWin().", + kBidder1Url.spec().c_str()))); +} + +// If the seller crashes at any point in the auction, the auction fails. +TEST_F(AuctionRunnerTest, SellerCrash) { + enum class CrashPhase { + kLoad, + kLoadAfterBiddersLoaded, + kScoreBid, + kReportResult, + }; + for (CrashPhase crash_phase : + {CrashPhase::kLoad, CrashPhase::kLoadAfterBiddersLoaded, + CrashPhase::kScoreBid, CrashPhase::kReportResult}) { + SCOPED_TRACE(static_cast<int>(crash_phase)); + + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + // While loop to allow breaking when the crash stage is reached. + while (true) { + if (crash_phase == CrashPhase::kLoad) { + // Close the service pipe to avoid a DCHECK when deleting the seller's + // load callback. + mock_worklet_service_.reset(); + seller_worklet.reset(); + break; + } + + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, + GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, + GURL("https://ad2.com/")); + // Wait for bids to be received. + base::RunLoop().RunUntilIdle(); + + if (crash_phase == CrashPhase::kLoadAfterBiddersLoaded) { + // Close the service pipe to avoid a DCHECK when deleting the seller's + // load callback. + mock_worklet_service_.reset(); + seller_worklet.reset(); + break; + } + + seller_worklet->CompleteLoading(); + + // Wait for Bidder1's bid. + auto score_ad_params = seller_worklet->WaitForScoreAd(); + if (crash_phase == CrashPhase::kScoreBid) { + seller_worklet.reset(); + break; + } + // Score Bidder1's bid. + bidder1_worklet.reset(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + // Score Bidder2's bid. + score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder2, score_ad_params->interest_group_owner); + EXPECT_EQ(7, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(11 /* score */); + + seller_worklet->WaitForReportResult(); + DCHECK_EQ(CrashPhase::kReportResult, crash_phase); + seller_worklet.reset(); + break; + } + + // Wait for auction to complete. + auction_run_loop_->Run(); + + // No bidder won, seller crashed. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, testing::ElementsAre(base::StringPrintf( + "%s crashed.", kSellerUrl.spec().c_str()))); + } +} + +// Test cases where a bad bid is received over Mojo. Bad bids should be rejected +// in the Mojo process, so these are treated as security errors. +TEST_F(AuctionRunnerTest, BadBid) { + const struct TestCase { + const char* expected_error_message; + double bid; + GURL render_url; + base::TimeDelta duration; + } kTestCases[] = { + // Bids that aren't positive integers. + { + "Invalid bid value", + -10, + GURL("https://ad1.com"), + base::TimeDelta(), + }, + { + "Invalid bid value", + 0, + GURL("https://ad1.com"), + base::TimeDelta(), + }, + { + "Invalid bid value", + std::numeric_limits<double>::infinity(), + GURL("https://ad1.com"), + base::TimeDelta(), + }, + { + "Invalid bid value", + std::numeric_limits<double>::quiet_NaN(), + GURL("https://ad1.com"), + base::TimeDelta(), + }, + + // Invalid URL. + { + "Invalid bid render URL", + 1, + GURL(":"), + base::TimeDelta(), + }, + + // Non-HTTPS URLs. + { + "Invalid bid render URL", + 1, + GURL("data:,foo"), + base::TimeDelta(), + }, + { + "Invalid bid render URL", + 1, + GURL("http://ad1.com"), + base::TimeDelta(), + }, + + // HTTPS URL that's not in the list of allowed renderUrls. + { + "Bid render URL must be an ad URL", + 1, + GURL("https://ad2.com"), + base::TimeDelta(), + }, + + // Negative time. + { + "Invalid bid duration", + 1, + GURL("https://ad2.com"), + base::TimeDelta::FromMilliseconds(-1), + }, + }; + + for (const auto& test_case : kTestCases) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + bidder1_worklet->CompleteLoadingAndBid(test_case.bid, test_case.render_url, + test_case.duration); + // Bidder 2 doesn't bid.. + bidder2_worklet->CompleteLoadingWithoutBid(); + + // Since there's no acceptable bid, the seller worklet is never asked to + // score a bid. + auction_run_loop_->Run(); + + EXPECT_EQ(test_case.expected_error_message, TakeBadMessage()); + + // No bidder won. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, testing::ElementsAre()); + } +} + +// Test cases where bad a report URL is received over Mojo from the bidder +// worklet. Bad report URLs should be rejected in the Mojo process, so these are +// treated as security errors. +TEST_F(AuctionRunnerTest, BadSellerReportUrl) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + // Only Bidder1 bids, to keep things simple. + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingWithoutBid(); + + auto score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + // Bidder1 never gets to report anything, since the seller providing a bad + // report URL aborts the auction. + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(GURL("http://not.https.test/")); + auction_run_loop_->Run(); + + EXPECT_EQ("Invalid seller report URL", TakeBadMessage()); + + // No bidder won. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// Test cases where bad a report URL is received over Mojo from the seller +// worklet. Bad report URLs should be rejected in the Mojo process, so these are +// treated as security errors. +TEST_F(AuctionRunnerTest, BadBidderReportUrl) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + seller_worklet->CompleteLoading(); + // Only Bidder1 bids, to keep things simple. + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad1.com/")); + bidder2_worklet->CompleteLoadingWithoutBid(); + + auto score_ad_params = seller_worklet->WaitForScoreAd(); + EXPECT_EQ(kBidder1, score_ad_params->interest_group_owner); + EXPECT_EQ(5, score_ad_params->bid); + seller_worklet->InvokeScoreAdCallback(10 /* score */); + + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback( + GURL("https://valid.url.that.is.thrown.out.test/")); + bidder1_worklet->WaitForReportWin(); + bidder1_worklet->InvokeReportWinCallback(GURL("http://not.https.test/")); + auction_run_loop_->Run(); + + EXPECT_EQ("Invalid bidder report URL", TakeBadMessage()); + + // No bidder won. + EXPECT_TRUE(result_.ad_url.is_empty()); + EXPECT_TRUE(result_.ad_metadata.empty()); + EXPECT_TRUE(result_.interest_group_owner.opaque()); + EXPECT_EQ("", result_.interest_group_name); + EXPECT_TRUE(result_.seller_report_url.is_empty()); + EXPECT_TRUE(result_.bidder_report_url.is_empty()); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// Make sure that requesting unexpected URLs is blocked. +TEST_F(AuctionRunnerTest, UrlRequestProtection) { + StartStandardAuctionWithMockService(); + + auto seller_worklet = mock_worklet_service_->TakeSellerWorklet(); + ASSERT_TRUE(seller_worklet); + auto bidder1_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder1, kBidder1Name); + ASSERT_TRUE(bidder1_worklet); + auto bidder2_worklet = + mock_worklet_service_->TakeBidderWorklet(kBidder2, kBidder2Name); + ASSERT_TRUE(bidder2_worklet); + + // It should be possible to request the seller URL from the seller's + // URLLoaderFactory. + network::ResourceRequest request; + request.url = kSellerUrl; + request.headers.SetHeader(net::HttpRequestHeaders::kAccept, + "application/javascript"); + mojo::PendingRemote<network::mojom::URLLoader> receiver; + mojo::PendingReceiver<network::mojom::URLLoaderClient> client; + seller_worklet->url_loader_factory()->CreateLoaderAndStart( + receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */, + 0 /* options */, request, client.InitWithNewPipeAndPassRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + seller_worklet->url_loader_factory().FlushForTesting(); + EXPECT_TRUE(seller_worklet->url_loader_factory().is_connected()); + ASSERT_EQ(1u, url_loader_factory_.pending_requests()->size()); + EXPECT_EQ(kSellerUrl, + (*url_loader_factory_.pending_requests())[0].request.url); + receiver.reset(); + client.reset(); + + // A bidder's URLLoaderFactory should reject the seller URL, closing the Mojo + // pipe. + bidder1_worklet->url_loader_factory()->CreateLoaderAndStart( + receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */, + 0 /* options */, request, client.InitWithNewPipeAndPassRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + bidder1_worklet->url_loader_factory().FlushForTesting(); + EXPECT_FALSE(bidder1_worklet->url_loader_factory().is_connected()); + EXPECT_EQ(1u, url_loader_factory_.pending_requests()->size()); + EXPECT_EQ("Unexpected request", TakeBadMessage()); + receiver.reset(); + client.reset(); + + // A bidder's URLLoaderFactory should allow the bidder's URL to be requested. + request.url = kBidder2Url; + bidder2_worklet->url_loader_factory()->CreateLoaderAndStart( + receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */, + 0 /* options */, request, client.InitWithNewPipeAndPassRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + bidder2_worklet->url_loader_factory().FlushForTesting(); + EXPECT_TRUE(bidder2_worklet->url_loader_factory().is_connected()); + ASSERT_EQ(2u, url_loader_factory_.pending_requests()->size()); + EXPECT_EQ(kBidder2Url, + (*url_loader_factory_.pending_requests())[1].request.url); + receiver.reset(); + client.reset(); + + // The seller's URLLoaderFactory should reject a bidder worklet's URL, closing + // the Mojo pipe. + seller_worklet->url_loader_factory()->CreateLoaderAndStart( + receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */, + 0 /* options */, request, client.InitWithNewPipeAndPassRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + seller_worklet->url_loader_factory().FlushForTesting(); + EXPECT_FALSE(seller_worklet->url_loader_factory().is_connected()); + EXPECT_EQ(2u, url_loader_factory_.pending_requests()->size()); + EXPECT_EQ("Unexpected request", TakeBadMessage()); + receiver.reset(); + client.reset(); + + // A bidder's URLLoaderFactory should also reject the URL from another bidder. + request.url = kBidder1Url; + bidder2_worklet->url_loader_factory()->CreateLoaderAndStart( + receiver.InitWithNewPipeAndPassReceiver(), 0 /* request_id_ */, + 0 /* options */, request, client.InitWithNewPipeAndPassRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + bidder2_worklet->url_loader_factory().FlushForTesting(); + EXPECT_FALSE(bidder2_worklet->url_loader_factory().is_connected()); + ASSERT_EQ(2u, url_loader_factory_.pending_requests()->size()); + EXPECT_EQ("Unexpected request", TakeBadMessage()); + + // Reset the service, so the uninvoke worklet loading callbacks can be + // destroyed without DCHECKing. + mock_worklet_service_.reset(); +} + +} // namespace +} // namespace content
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy.cc b/content/browser/interest_group/auction_url_loader_factory_proxy.cc index 0dd1150e..0b5cea78 100644 --- a/content/browser/interest_group/auction_url_loader_factory_proxy.cc +++ b/content/browser/interest_group/auction_url_loader_factory_proxy.cc
@@ -14,7 +14,6 @@ #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "content/public/browser/global_request_id.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -26,7 +25,6 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" #include "url/gurl.h" #include "url/origin.h" @@ -34,33 +32,17 @@ AuctionURLLoaderFactoryProxy::AuctionURLLoaderFactoryProxy( mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver, - GetUrlLoaderFactoryCallback get_publisher_frame_url_loader_factory, - GetUrlLoaderFactoryCallback get_trusted_url_loader_factory, + GetUrlLoaderFactoryCallback get_url_loader_factory, const url::Origin& frame_origin, - const blink::mojom::AuctionAdConfig& auction_config, - const std::vector<auction_worklet::mojom::BiddingInterestGroupPtr>& bidders) + bool use_cors, + const GURL& script_url, + const absl::optional<GURL>& trusted_signals_url) : receiver_(this, std::move(pending_receiver)), - get_publisher_frame_url_loader_factory_( - std::move(get_publisher_frame_url_loader_factory)), - get_trusted_url_loader_factory_( - std::move(get_trusted_url_loader_factory)), + get_url_loader_factory_(std::move(get_url_loader_factory)), frame_origin_(frame_origin), - expected_query_prefix_( - "hostname=" + net::EscapeQueryParamValue(frame_origin.host(), true) + - "&keys=") { - decision_logic_url_ = auction_config.decision_logic_url; - for (const auto& bidder : bidders) { - if (bidder->group->bidding_url) - bidding_urls_.insert(*bidder->group->bidding_url); - if (bidder->group->trusted_bidding_signals_url) { - // Base trusted bidding signals URLs can't have query strings, since - // running an auction will create URLs by adding query strings to them. - DCHECK(!bidder->group->trusted_bidding_signals_url->has_query()); - - realtime_data_urls_.insert(*bidder->group->trusted_bidding_signals_url); - } - } -} + use_cors_(use_cors), + script_url_(script_url), + trusted_signals_url_(trusted_signals_url) {} AuctionURLLoaderFactoryProxy::~AuctionURLLoaderFactoryProxy() = default; @@ -79,56 +61,18 @@ return; } - // True if the more restricted publisher RenderFrameHost's URLLoader should be - // used to load a resource. False if the global factory should be used - // instead, setting the ResourceRequest::TrustedParams field to use the - // correct network shard. - bool use_publisher_frame_loader = true; + bool is_request_allowed = false; - if (accept_header == "application/javascript") { - // Only script_urls may be requested with the Javascript Accept header. - if (url_request.url == decision_logic_url_) { - // Nothing more to do. - } else if (bidding_urls_.find(url_request.url) != bidding_urls_.end()) { - // This is safe, because `bidding_urls_` can only be registered by - // calling `joinAdInterestGroup` from the URL's origin. - use_publisher_frame_loader = false; - } else { - receiver_.ReportBadMessage("Unexpected Javascript request url"); - return; - } - } else if (accept_header == "application/json") { - GURL::Replacements replacements; - replacements.ClearQuery(); - GURL url_without_query = url_request.url.ReplaceComponents(replacements); - // Only `realtime_data_urls_` may be requested with the JSON Accept header. - if (realtime_data_urls_.find(url_without_query) == - realtime_data_urls_.end()) { - receiver_.ReportBadMessage("Unexpected JSON request url"); - return; - } + if (url_request.url == script_url_ && + accept_header == "application/javascript") { + is_request_allowed = true; + } else if (trusted_signals_url_ && url_request.url == *trusted_signals_url_ && + accept_header == "application/json") { + is_request_allowed = true; + } - // Make sure the query string starts with the correct prefix. - if (!base::StartsWith(url_request.url.query_piece(), - expected_query_prefix_)) { - receiver_.ReportBadMessage("JSON query string missing expected prefix"); - return; - } - - // This should contain the keys value of the query string. - base::StringPiece keys = - url_request.url.query_piece().substr(expected_query_prefix_.size()); - // The keys value should be the last value of the query string. - if (keys.find('&') != base::StringPiece::npos) { - receiver_.ReportBadMessage( - "JSON query string has unexpected additional parameter"); - return; - } - // This is safe, because `realtime_data_urls_` can only be registered by - // calling `joinAdInterestGroup` from the URL's origin. - use_publisher_frame_loader = false; - } else { - receiver_.ReportBadMessage("Accept header has unexpected value"); + if (!is_request_allowed) { + receiver_.ReportBadMessage("Unexpected request"); return; } @@ -145,9 +89,7 @@ new_request.credentials_mode = network::mojom::CredentialsMode::kOmit; new_request.request_initiator = frame_origin_; - network::mojom::URLLoaderFactory* url_loader_factory = nullptr; - if (use_publisher_frame_loader) { - url_loader_factory = get_publisher_frame_url_loader_factory_.Run(); + if (use_cors_) { new_request.mode = network::mojom::RequestMode::kCors; } else { // Treat this as a subresource request from the owner's origin, using the @@ -156,7 +98,6 @@ // TODO(mmenke): This leaks information to the third party that made the // request (both the URL itself leaks information, and using the origin's // NIK leaks information). These leaks need to be fixed. - url_loader_factory = get_trusted_url_loader_factory_.Run(); new_request.mode = network::mojom::RequestMode::kNoCors; new_request.trusted_params = network::ResourceRequest::TrustedParams(); url::Origin origin = url::Origin::Create(url_request.url); @@ -171,7 +112,7 @@ // TODO(mmenke): Investigate whether `devtools_observer` or // `report_raw_headers` should be set when devtools is open. - url_loader_factory->CreateLoaderAndStart( + get_url_loader_factory_.Run()->CreateLoaderAndStart( std::move(receiver), // These are browser-initiated requests, so give them a browser request // ID. Extension APIs may expect these to be unique. @@ -182,7 +123,6 @@ void AuctionURLLoaderFactoryProxy::Clone( mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) { - // Not currently needed. NOTREACHED(); }
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy.h b/content/browser/interest_group/auction_url_loader_factory_proxy.h index b5ee615b..c830072af 100644 --- a/content/browser/interest_group/auction_url_loader_factory_proxy.h +++ b/content/browser/interest_group/auction_url_loader_factory_proxy.h
@@ -7,19 +7,14 @@ #include <stdint.h> -#include <set> -#include <vector> - #include "base/callback_forward.h" #include "base/strings/string_piece_forward.h" #include "content/common/content_export.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom-forward.h" #include "url/gurl.h" namespace content { @@ -35,36 +30,25 @@ // Passed in callbacks must be safe to call at any time during the lifetime of // the AuctionURLLoaderFactoryProxy. // - // `get_publisher_frame_url_loader_factory` returns a URLLoaderFactory - // configured to behave like the URLLoaderFactory in use by the frame running - // the auction. It uses the same network partition, request initiator lock - // etc. This is used to request resources specified by the publisher page - // (currently, just the the `decision_logic_url`). This is needed to protect - // against a V8 compromise being used to access arbitrary resources by setting - // the `decision_logic_url` to a target site. URLs associated with interest - // groups already have first-party opt in, so don't need this, but the seller - // URLs do not. If `decision_logic_url` matches any bidding script URL, the - // frame factory is used for all requests for that URL. Bidder JSON requests - // are distinguishable via their accept header, so always use the trusted - // factory. + // `get_url_loader_factory` returns the URLLoaderFactory to use. Must be safe + // to call at any point until `this` has been destroyed. // - // `get_trusted_url_loader_factory` returns a trusted URLLoaderFactory that - // can request arbitrary URLs. This is used to request interest groups with - // the appropriate network partition. Each interest group URL request needs to - // use the partition of the associated interest group to avoid leaking the - // fetched URLs to the publisher, since interest groups are roughly analogous - // to more restricted third party cookies. + // `frame_origin` is the origin of the frame running the auction. Used as the + // initiator. // - // URLs that may be requested are extracted from `auction_config` and - // `bidders`. Any other requested URL will result in failure. + // `use_cors` indicates if requests should use CORS or not. Should be true for + // seller worklets. + // + // `script_url` is the Javascript URL for the worklet, and + // `trusted_signals_url` is the optional JSON url for additional input to the + // script. No other URLs may be requested. AuctionURLLoaderFactoryProxy( mojo::PendingReceiver<network::mojom::URLLoaderFactory> pending_receiver, - GetUrlLoaderFactoryCallback get_publisher_frame_url_loader_factory, - GetUrlLoaderFactoryCallback get_trusted_url_loader_factory, + GetUrlLoaderFactoryCallback get_url_loader_factory, const url::Origin& frame_origin, - const blink::mojom::AuctionAdConfig& auction_config, - const std::vector<auction_worklet::mojom::BiddingInterestGroupPtr>& - bidders); + bool use_cors, + const GURL& script_url, + const absl::optional<GURL>& trusted_signals_url = absl::nullopt); AuctionURLLoaderFactoryProxy(const AuctionURLLoaderFactoryProxy&) = delete; AuctionURLLoaderFactoryProxy& operator=(const AuctionURLLoaderFactoryProxy&) = delete; @@ -85,26 +69,13 @@ private: mojo::Receiver<network::mojom::URLLoaderFactory> receiver_; - const GetUrlLoaderFactoryCallback get_publisher_frame_url_loader_factory_; - const GetUrlLoaderFactoryCallback get_trusted_url_loader_factory_; + const GetUrlLoaderFactoryCallback get_url_loader_factory_; const url::Origin frame_origin_; + const bool use_cors_; - // URL of the seller script. Requested URLs may match these URLs exactly. - // Unlike `bidding_urls_`, requests for this URL must use the publisher - // frame's more restricted URLLoaderFactory. See constructor for more details. - GURL decision_logic_url_; - - // URLs of worklet bidder scripts. Requested URLs may match these URLs - // exactly. - std::set<GURL> bidding_urls_; - - // URLs for real-time bidding data. Requests may match these with the query - // parameter removed. - std::set<GURL> realtime_data_urls_; - - // Expected prefix for all realtime data URL query strings. - const std::string expected_query_prefix_; + const GURL script_url_; + const absl::optional<GURL> trusted_signals_url_; }; } // namespace content
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc b/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc index ca5bbf0e..c04e7f4 100644 --- a/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc +++ b/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc
@@ -14,7 +14,6 @@ #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/task_environment.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/system/functions.h" @@ -26,39 +25,25 @@ #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" #include "url/gurl.h" #include "url/origin.h" namespace content { -// URL for the scoring worklet. -const char kScoringWorkletUrl[] = "https://decision_logic_url.test/foo"; - -// URLs for bidding worklets and their trusted bidding signals. Third worklet -// has no trusted bidding signals URL. - -const char kBiddingWorkletUrl1[] = "https://bidding_url1.test/"; -const char kTrustedBiddingSignalsUrl1[] = - "https://trusted_bidding_signals_url1.test/"; - -const char kBiddingWorkletUrl2[] = "https://bidding_url2.test/foo"; -const char kTrustedBiddingSignalsUrl2[] = - "https://trusted_bidding_signals_url2.test/bar"; - -const char kBiddingWorkletUrl3[] = "https://bidding_url3.test/baz?foobar"; +const char kScriptUrl[] = "https://host.test/script"; +const char kTrustedSignalsUrl[] = "https://host.test/trusted_signals"; // Values for the Accept header. const char kAcceptJavascript[] = "application/javascript"; const char kAcceptJson[] = "application/json"; +const char kAcceptOther[] = "binary/ocelot-stream"; class ActionUrlLoaderFactoryProxyTest : public testing::Test { public: // Ways the proxy can behave in response to a request. enum class ExpectedResponse { kReject, - kUseFrameFactory, - kUseTrustedFactory, + kAllow, }; ActionUrlLoaderFactoryProxyTest() { CreateUrlLoaderFactoryProxy(); } @@ -72,37 +57,14 @@ // old one, or the old one's pipe was closed. DCHECK(!remote_url_loader_factory_ || !remote_url_loader_factory_.is_connected()); - blink::mojom::AuctionAdConfigPtr auction_config = - blink::mojom::AuctionAdConfig::New(); - auction_config->decision_logic_url = GURL(kScoringWorkletUrl); - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders; - - bidders.emplace_back(auction_worklet::mojom::BiddingInterestGroup::New()); - bidders.back()->group = blink::mojom::InterestGroup::New(); - bidders.back()->group->bidding_url = GURL(kBiddingWorkletUrl1); - bidders.back()->group->trusted_bidding_signals_url = - GURL(kTrustedBiddingSignalsUrl1); - - bidders.emplace_back(auction_worklet::mojom::BiddingInterestGroup::New()); - bidders.back()->group = blink::mojom::InterestGroup::New(); - bidders.back()->group->bidding_url = GURL(kBiddingWorkletUrl2); - bidders.back()->group->trusted_bidding_signals_url = - GURL(kTrustedBiddingSignalsUrl2); - - bidders.emplace_back(auction_worklet::mojom::BiddingInterestGroup::New()); - bidders.back()->group = blink::mojom::InterestGroup::New(); - bidders.back()->group->bidding_url = GURL(kBiddingWorkletUrl3); remote_url_loader_factory_.reset(); url_loader_factory_proxy_ = std::make_unique<AuctionURLLoaderFactoryProxy>( remote_url_loader_factory_.BindNewPipeAndPassReceiver(), base::BindRepeating( [](network::mojom::URLLoaderFactory* factory) { return factory; }, - &proxied_frame_url_loader_factory_), - base::BindRepeating( - [](network::mojom::URLLoaderFactory* factory) { return factory; }, - &proxied_trusted_url_loader_factory_), - frame_origin_, *auction_config, bidders); + &proxied_url_loader_factory_), + frame_origin_, use_cors_, GURL(kScriptUrl), trusted_signals_url_); } // Attempts to make a request for `request`. @@ -112,10 +74,7 @@ if (!remote_url_loader_factory_.is_connected()) CreateUrlLoaderFactoryProxy(); - int initial_num_frame_requests = - proxied_frame_url_loader_factory_.NumPending(); - int initial_num_trusted_requests = - proxied_trusted_url_loader_factory_.NumPending(); + int initial_num_requests = proxied_url_loader_factory_.NumPending(); // Try to send a request. Requests are never run to completion, instead, // requests that make it to the nested `url_loader_factory_` are tracked in @@ -137,31 +96,17 @@ network::TestURLLoaderFactory::PendingRequest const* pending_request; switch (expected_response) { case ExpectedResponse::kReject: - // A request being rejected closes the receiver. - EXPECT_EQ(initial_num_frame_requests, - proxied_frame_url_loader_factory_.NumPending()); - EXPECT_EQ(initial_num_trusted_requests, - proxied_trusted_url_loader_factory_.NumPending()); + EXPECT_EQ(initial_num_requests, + proxied_url_loader_factory_.NumPending()); // Rejecting a request should result in closing the factory mojo pipe. EXPECT_FALSE(remote_url_loader_factory_.is_connected()); return; - case ExpectedResponse::kUseFrameFactory: - ASSERT_EQ(initial_num_frame_requests + 1, - proxied_frame_url_loader_factory_.NumPending()); - ASSERT_EQ(initial_num_trusted_requests, - proxied_trusted_url_loader_factory_.NumPending()); + case ExpectedResponse::kAllow: + EXPECT_EQ(initial_num_requests + 1, + proxied_url_loader_factory_.NumPending()); EXPECT_TRUE(remote_url_loader_factory_.is_connected()); pending_request = - &proxied_frame_url_loader_factory_.pending_requests()->back(); - break; - case ExpectedResponse::kUseTrustedFactory: - ASSERT_EQ(initial_num_frame_requests, - proxied_frame_url_loader_factory_.NumPending()); - ASSERT_EQ(initial_num_trusted_requests + 1, - proxied_trusted_url_loader_factory_.NumPending()); - EXPECT_TRUE(remote_url_loader_factory_.is_connected()); - pending_request = - &proxied_trusted_url_loader_factory_.pending_requests()->back(); + &proxied_url_loader_factory_.pending_requests()->back(); break; } @@ -175,13 +120,7 @@ // unique within the browser process, not just among requests using the // AuctionURLLoaderFactoryProxy. for (const auto& other_pending_request : - *proxied_frame_url_loader_factory_.pending_requests()) { - if (&other_pending_request == pending_request) - continue; - EXPECT_NE(other_pending_request.request_id, pending_request->request_id); - } - for (const auto& other_pending_request : - *proxied_trusted_url_loader_factory_.pending_requests()) { + *proxied_url_loader_factory_.pending_requests()) { if (&other_pending_request == pending_request) continue; EXPECT_NE(other_pending_request.request_id, pending_request->request_id); @@ -213,7 +152,7 @@ // The initiator should be set. EXPECT_EQ(frame_origin_, observed_request.request_initiator); - if (expected_response == ExpectedResponse::kUseFrameFactory) { + if (use_cors_) { EXPECT_EQ(network::mojom::RequestMode::kCors, observed_request.mode); EXPECT_FALSE(observed_request.trusted_params); } else { @@ -246,170 +185,107 @@ protected: base::test::TaskEnvironment task_environment_; + bool use_cors_ = false; + absl::optional<GURL> trusted_signals_url_ = GURL(kTrustedSignalsUrl); + url::Origin frame_origin_ = url::Origin::Create(GURL("https://foo.test/")); - network::TestURLLoaderFactory proxied_frame_url_loader_factory_; - network::TestURLLoaderFactory proxied_trusted_url_loader_factory_; + network::TestURLLoaderFactory proxied_url_loader_factory_; std::unique_ptr<AuctionURLLoaderFactoryProxy> url_loader_factory_proxy_; mojo::Remote<network::mojom::URLLoaderFactory> remote_url_loader_factory_; }; -// Test exact URL matches. Trusted bidding signals URLs should be rejected -// unless that have a valid query string appended. -TEST_F(ActionUrlLoaderFactoryProxyTest, ExactURLMatch) { - TryMakeRequest(kScoringWorkletUrl, kAcceptJavascript, - ExpectedResponse::kUseFrameFactory); - TryMakeRequest(kScoringWorkletUrl, kAcceptJson, ExpectedResponse::kReject); - TryMakeRequest(kScoringWorkletUrl, "Unknown/Unknown", - ExpectedResponse::kReject); - TryMakeRequest(kScoringWorkletUrl, absl::nullopt, ExpectedResponse::kReject); +TEST_F(ActionUrlLoaderFactoryProxyTest, Basic) { + for (bool use_cors : {false, true}) { + use_cors_ = use_cors; + // Force creation of a new proxy, with correct CORS value. + remote_url_loader_factory_.reset(); + CreateUrlLoaderFactoryProxy(); - TryMakeRequest(kBiddingWorkletUrl1, kAcceptJavascript, - ExpectedResponse::kUseTrustedFactory); - TryMakeRequest(kBiddingWorkletUrl1, kAcceptJson, ExpectedResponse::kReject); - TryMakeRequest(kBiddingWorkletUrl1, "Unknown/Unknown", - ExpectedResponse::kReject); - TryMakeRequest(kBiddingWorkletUrl1, absl::nullopt, ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1, kAcceptJavascript, - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1, kAcceptJson, - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1, "Unknown/Unknown", - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1, absl::nullopt, - ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, kAcceptJavascript, ExpectedResponse::kAllow); + TryMakeRequest(kScriptUrl, kAcceptJson, ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, absl::nullopt, ExpectedResponse::kReject); - TryMakeRequest(kBiddingWorkletUrl2, kAcceptJavascript, - ExpectedResponse::kUseTrustedFactory); - TryMakeRequest(kBiddingWorkletUrl2, kAcceptJson, ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl2, kAcceptJavascript, - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl2, kAcceptJson, - ExpectedResponse::kReject); - - TryMakeRequest(kBiddingWorkletUrl3, kAcceptJavascript, - ExpectedResponse::kUseTrustedFactory); - TryMakeRequest(kBiddingWorkletUrl3, kAcceptJson, ExpectedResponse::kReject); -} - -TEST_F(ActionUrlLoaderFactoryProxyTest, QueryStrings) { - const char* kValidBiddingSignalsQueryStrings[] = { - "?hostname=foo.test&keys=bar,baz", - "?hostname=foo.test&keys=bar", - // Escaped &. - "?hostname=foo.test&keys=bar%26", - }; - - const char* kInvalidBiddingSignalsQueryStrings[] = { - "?hostname=bar.test&keys=bar,baz", - "?hostname=foo.test&keys=bar&hats=foo", - "?hostname=foo.test&keys=bar&hats", - "?hostname=foo.test", - "?hostname=foo.test&keys", - "?bar=foo.test&keys=bar,baz", - "?keys=bar,baz", - "?", - }; - - for (std::string query_string : kValidBiddingSignalsQueryStrings) { - SCOPED_TRACE(query_string); - TryMakeRequest(kScoringWorkletUrl + query_string, kAcceptJavascript, + TryMakeRequest(kTrustedSignalsUrl, kAcceptJavascript, + ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, kAcceptJson, ExpectedResponse::kAllow); + TryMakeRequest(kTrustedSignalsUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, absl::nullopt, ExpectedResponse::kReject); - TryMakeRequest(kBiddingWorkletUrl1 + query_string, kAcceptJavascript, + TryMakeRequest("https://host.test/", kAcceptJavascript, ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1 + query_string, kAcceptJson, - ExpectedResponse::kUseTrustedFactory); - - TryMakeRequest(kBiddingWorkletUrl2 + query_string, kAcceptJavascript, + TryMakeRequest("https://host.test/", kAcceptJson, ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl2 + query_string, kAcceptJson, - ExpectedResponse::kUseTrustedFactory); - - TryMakeRequest(kBiddingWorkletUrl3 + query_string, kAcceptJavascript, + TryMakeRequest("https://host.test/", kAcceptOther, ExpectedResponse::kReject); - } - - for (std::string query_string : kInvalidBiddingSignalsQueryStrings) { - SCOPED_TRACE(query_string); - TryMakeRequest(kScoringWorkletUrl + query_string, kAcceptJavascript, - ExpectedResponse::kReject); - - TryMakeRequest(kBiddingWorkletUrl1 + query_string, kAcceptJavascript, - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl1 + query_string, kAcceptJson, - ExpectedResponse::kReject); - - TryMakeRequest(kBiddingWorkletUrl2 + query_string, kAcceptJavascript, - ExpectedResponse::kReject); - TryMakeRequest(kTrustedBiddingSignalsUrl2 + query_string, kAcceptJson, - ExpectedResponse::kReject); - - TryMakeRequest(kBiddingWorkletUrl3 + query_string, kAcceptJavascript, + TryMakeRequest("https://host.test/", absl::nullopt, ExpectedResponse::kReject); } } -// Set a number of extra parameters on the ResourceRequest, which the -// AuctionURLLoaderFactoryProxy should ignore. This test relies heavily on the -// validity checks in TryMakeRequest(). -TEST_F(ActionUrlLoaderFactoryProxyTest, ExtraParametersIgnored) { - network::ResourceRequest request; +TEST_F(ActionUrlLoaderFactoryProxyTest, NoTrustedSignalsUrl) { + trusted_signals_url_ = absl::nullopt; - request.credentials_mode = network::mojom::CredentialsMode::kInclude; - request.trusted_params = network::ResourceRequest::TrustedParams(); + for (bool use_cors : {false, true}) { + use_cors_ = use_cors; + // Force creation of a new proxy, with correct CORS value. + remote_url_loader_factory_.reset(); + CreateUrlLoaderFactoryProxy(); - url::Origin other_origin = - url::Origin::Create(GURL("https://somewhere.else.text")); - request.trusted_params->isolation_info = net::IsolationInfo::Create( - net::IsolationInfo::RequestType::kMainFrame, other_origin, other_origin, - net::SiteForCookies::FromOrigin(other_origin)); - request.trusted_params->disable_secure_dns = true; + TryMakeRequest(kScriptUrl, kAcceptJavascript, ExpectedResponse::kAllow); + TryMakeRequest(kScriptUrl, kAcceptJson, ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, absl::nullopt, ExpectedResponse::kReject); - request.headers.SetHeader("Flux-Capacitor", "Y"); - request.headers.SetHeader("Host", "Fred"); - request.headers.SetHeader(net::HttpRequestHeaders::kAccept, - kAcceptJavascript); + TryMakeRequest(kTrustedSignalsUrl, kAcceptJavascript, + ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, kAcceptJson, ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, absl::nullopt, + ExpectedResponse::kReject); - request.url = GURL(kScoringWorkletUrl); - TryMakeRequest(request, ExpectedResponse::kUseFrameFactory); - - request.url = GURL(kBiddingWorkletUrl1); - TryMakeRequest(request, ExpectedResponse::kUseTrustedFactory); - - request.url = GURL(std::string(kTrustedBiddingSignalsUrl1) + - "?hostname=foo.test&keys=bar"); - request.headers.SetHeader(net::HttpRequestHeaders::kAccept, kAcceptJson); - TryMakeRequest(request, ExpectedResponse::kUseTrustedFactory); + TryMakeRequest("https://host.test/", kAcceptJavascript, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", kAcceptJson, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", kAcceptOther, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", absl::nullopt, + ExpectedResponse::kReject); + } } -// If a bidder URL matches the scoring URL, the publisher frame's -// URLLoaderFactory should be used instead of the trusted one. -TEST_F(ActionUrlLoaderFactoryProxyTest, BidderUrlMatchesScoringUrl) { - blink::mojom::AuctionAdConfigPtr auction_config = - blink::mojom::AuctionAdConfig::New(); - auction_config->decision_logic_url = GURL(kScoringWorkletUrl); - std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> bidders; +TEST_F(ActionUrlLoaderFactoryProxyTest, SameUrl) { + trusted_signals_url_ = GURL(kScriptUrl); - bidders.emplace_back(auction_worklet::mojom::BiddingInterestGroup::New()); - bidders.back()->group = blink::mojom::InterestGroup::New(); - bidders.back()->group->bidding_url = GURL(kScoringWorkletUrl); + for (bool use_cors : {false, true}) { + use_cors_ = use_cors; + // Force creation of a new proxy, with correct CORS value. + remote_url_loader_factory_.reset(); + CreateUrlLoaderFactoryProxy(); - remote_url_loader_factory_.reset(); - url_loader_factory_proxy_ = std::make_unique<AuctionURLLoaderFactoryProxy>( - remote_url_loader_factory_.BindNewPipeAndPassReceiver(), - base::BindRepeating( - [](network::mojom::URLLoaderFactory* factory) { return factory; }, - &proxied_frame_url_loader_factory_), - base::BindRepeating( - [](network::mojom::URLLoaderFactory* factory) { return factory; }, - &proxied_trusted_url_loader_factory_), - frame_origin_, *auction_config, bidders); + TryMakeRequest(kScriptUrl, kAcceptJavascript, ExpectedResponse::kAllow); + TryMakeRequest(kScriptUrl, kAcceptJson, ExpectedResponse::kAllow); + TryMakeRequest(kScriptUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kScriptUrl, absl::nullopt, ExpectedResponse::kReject); - // Make request twice, as will actually happen in this case. - TryMakeRequest(kScoringWorkletUrl, kAcceptJavascript, - ExpectedResponse::kUseFrameFactory); - TryMakeRequest(kScoringWorkletUrl, kAcceptJavascript, - ExpectedResponse::kUseFrameFactory); + TryMakeRequest(kTrustedSignalsUrl, kAcceptJavascript, + ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, kAcceptJson, ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, kAcceptOther, ExpectedResponse::kReject); + TryMakeRequest(kTrustedSignalsUrl, absl::nullopt, + ExpectedResponse::kReject); + + TryMakeRequest("https://host.test/", kAcceptJavascript, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", kAcceptJson, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", kAcceptOther, + ExpectedResponse::kReject); + TryMakeRequest("https://host.test/", absl::nullopt, + ExpectedResponse::kReject); + } } } // namespace content
diff --git a/content/browser/media/media_source_browsertest.cc b/content/browser/media/media_source_browsertest.cc index 2372cdec..27d92d4 100644 --- a/content/browser/media/media_source_browsertest.cc +++ b/content/browser/media/media_source_browsertest.cc
@@ -74,6 +74,20 @@ TestSimplePlayback("bear-320x240-audio-only.webm", media::kEnded); } +IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_MP3) { + TestSimplePlayback("sfx.mp3", media::kEnded); +} + +IN_PROC_BROWSER_TEST_F( + MediaSourceTest, + Playback_AudioOnly_MP3_With_Codecs_Parameter_Should_Fail) { + // We override the correct media type for this file with one which erroneously + // includes a codecs parameter that is valid for progressive but invalid for + // MSE type support. + DCHECK_EQ(media::GetMimeTypeForFile("sfx.mp3"), "audio/mpeg"); + TestSimplePlayback("sfx.mp3", "audio/mpeg; codecs=\"mp3\"", media::kFailed); +} + // Test the case where test file and mime type mismatch. IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Type_Error) { const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
diff --git a/content/browser/process_internals/process_internals.mojom b/content/browser/process_internals/process_internals.mojom index 0b2f4ef..8ae0f5f 100644 --- a/content/browser/process_internals/process_internals.mojom +++ b/content/browser/process_internals/process_internals.mojom
@@ -70,8 +70,8 @@ // added in response to heuristics triggered directly by web sites, such // as headers that suggest the site might benefit from isolation. Like // user-triggered isolated origins, these isolated origins apply within - // the current profile only, though currently they aren't preserved across - // restarts. + // the current profile only, they are preserved across + // restarts, and they are cleared when the user clears browsing data. GetWebTriggeredIsolatedOrigins() => (array<string> isolated_origins); // Returns a list of isolated origins that apply globally in all profiles.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 5561074..f900b91 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -2423,8 +2423,10 @@ return false; // There's no need for additional isolation if the site already requires a - // dedicated process (e.g., if the site was isolated via other isolation - // mechanisms or from a prior visit to the site with COOP headers). + // dedicated process via other isolation mechanisms. However, we still + // return true if the site has been isolated due to COOP previously, so that + // we can go through the COOP isolation flow to update the timestamp of when + // the COOP isolation for this site was last used. // // Note: we can use `site_info_` here, since that has been assigned at // request start time and updated by redirects, but it is not (currently) @@ -2437,9 +2439,14 @@ DCHECK(!site_info_.does_site_request_dedicated_process_for_coop()); if (site_info_.RequiresDedicatedProcess( GetStartingSiteInstance()->GetIsolationContext())) { - return false; + // Note: use process_lock_url() to check isolation on the actual site + // rather than the effective URL in the case of hosted apps. + bool is_already_isolated_due_to_coop = + ChildProcessSecurityPolicyImpl::GetInstance()->IsIsolatedSiteFromSource( + url::Origin::Create(site_info_.process_lock_url()), + ChildProcessSecurityPolicy::IsolatedOriginSource::WEB_TRIGGERED); + return is_already_isolated_due_to_coop; } - return true; }
diff --git a/content/browser/renderer_host/render_frame_host_delegate.h b/content/browser/renderer_host/render_frame_host_delegate.h index 2a956cb6..854c364 100644 --- a/content/browser/renderer_host/render_frame_host_delegate.h +++ b/content/browser/renderer_host/render_frame_host_delegate.h
@@ -43,6 +43,7 @@ #include "third_party/blink/public/mojom/frame/blocked_navigation_types.mojom.h" #include "third_party/blink/public/mojom/frame/frame.mojom-forward.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h" +#include "third_party/blink/public/mojom/media/capture_handle_config.mojom.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_mode.h" #include "ui/base/window_open_disposition.h"
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 9708cea3..24eb7cb 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -5311,7 +5311,7 @@ GetSiteInstance()->GetBrowserContext(), GetMainFrame()->GetLastCommittedURL(), ChildProcessSecurityPolicy::IsolatedOriginSource::WEB_TRIGGERED, - false /* should_persist */); + SiteIsolationPolicy::ShouldPersistIsolatedCOOPSites()); } } }
diff --git a/content/browser/resources/process/process_internals.js b/content/browser/resources/process/process_internals.js index fcd0e6d..959ec00 100644 --- a/content/browser/resources/process/process_internals.js +++ b/content/browser/resources/process/process_internals.js
@@ -238,7 +238,8 @@ $('web-triggered-isolated-origins').textContent = 'The following origins are isolated based on runtime heuristics ' + 'triggered directly by web pages, such as Cross-Origin-Opener-Policy ' + - 'headers. This list is cleared after a restart.'; + 'headers. Clear cookies or history to wipe this list; this takes ' + + 'effect after a restart.'; const list = document.createElement('ul'); for (const origin of response.isolatedOrigins) {
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm index b9e6d18a..a3c412f 100644 --- a/content/browser/sandbox_parameters_mac.mm +++ b/content/browser/sandbox_parameters_mac.mm
@@ -191,11 +191,6 @@ } #endif -void SetupUtilitySandboxParameters(sandbox::SeatbeltExecClient* client, - const base::CommandLine& command_line) { - SetupCommonSandboxParameters(client); -} - void SetupGpuSandboxParameters(sandbox::SeatbeltExecClient* client, const base::CommandLine& command_line) { SetupCommonSandboxParameters(client); @@ -214,10 +209,12 @@ switch (sandbox_type) { case sandbox::policy::SandboxType::kAudio: case sandbox::policy::SandboxType::kCdm: + case sandbox::policy::SandboxType::kMirroring: case sandbox::policy::SandboxType::kNaClLoader: case sandbox::policy::SandboxType::kPrintBackend: case sandbox::policy::SandboxType::kPrintCompositor: case sandbox::policy::SandboxType::kRenderer: + case sandbox::policy::SandboxType::kUtility: SetupCommonSandboxParameters(client); break; case sandbox::policy::SandboxType::kGpu: { @@ -232,9 +229,6 @@ SetupPPAPISandboxParameters(client); #endif break; - case sandbox::policy::SandboxType::kUtility: - SetupUtilitySandboxParameters(client, command_line); - break; case sandbox::policy::SandboxType::kNoSandbox: case sandbox::policy::SandboxType::kVideoCapture: CHECK(false) << "Unhandled parameters for sandbox_type "
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index a4b1516..0f9b8fe 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -429,7 +429,6 @@ ServiceWorkerContext::ResultCallback result_callback, blink::ServiceWorkerStatusCode service_worker_status); - // Called when ServiceWorkerImportedScriptUpdateCheck is enabled. std::unique_ptr<blink::PendingURLLoaderFactoryBundle> CreateNonNetworkPendingURLLoaderFactoryBundleForUpdateCheck( BrowserContext* browser_context);
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index a94e64e..cc2478e 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1441,7 +1441,6 @@ bool force_start_worker_failure_ = false; absl::optional<bool> will_be_terminated_; - // These are used only when ServiceWorkerImportedScriptUpdateCheck is enabled. FakeNetwork fake_network_; std::unique_ptr<URLLoaderInterceptor> interceptor_;
diff --git a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc index 918eaad..ae7a655 100644 --- a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc +++ b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -122,8 +122,7 @@ } // This tests copying script and creating resume type -// ServiceWorkerNewScriptLoaders when ServiceWorkerImportedScriptUpdateCheck -// is enabled. +// ServiceWorkerNewScriptLoaders. class ServiceWorkerScriptLoaderFactoryCopyResumeTest : public ServiceWorkerScriptLoaderFactoryTest { public:
diff --git a/content/browser/service_worker/service_worker_update_checker.h b/content/browser/service_worker/service_worker_update_checker.h index 058e8489ab..78cb84b 100644 --- a/content/browser/service_worker/service_worker_update_checker.h +++ b/content/browser/service_worker/service_worker_update_checker.h
@@ -22,8 +22,6 @@ class ServiceWorkerContextCore; class ServiceWorkerVersion; -// Used only when ServiceWorkerImportedScriptUpdateCheck is enabled. -// // This is responsible for byte-for-byte update checking. Mostly corresponding // to step 1-9 in [[Update]] in the spec, but this stops to fetch scripts after // any changes found.
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 54f27ccd..f3748a2d 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -571,7 +571,6 @@ void IncrementPendingUpdateHintCount(); void DecrementPendingUpdateHintCount(); - // ServiceWorkerImportedScriptUpdateCheck: // Called on versions created for an update check. Called if the check // determined an update exists before starting the worker for an install // event. @@ -1094,12 +1093,10 @@ std::unique_ptr<blink::TrialTokenValidator> const validator_; - // Stores the result of byte-to-byte update check for each script. Used only - // when ServiceWorkerImportedScriptUpdateCheck is enabled. + // Stores the result of byte-to-byte update check for each script. std::map<GURL, ServiceWorkerUpdateChecker::ComparedScriptInfo> compared_script_info_map_; - // ServiceWorkerImportedScriptUpdateCheck: // If this version was created for an update check that found an update, // |updated_script_url_| is the URL of the script for which a byte-for-byte // change was found. Otherwise, it's the empty GURL.
diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc index 5413414..03d0af2 100644 --- a/content/browser/utility_sandbox_delegate.cc +++ b/content/browser/utility_sandbox_delegate.cc
@@ -45,6 +45,9 @@ sandbox_type_ == sandbox::policy::SandboxType::kIconReader || sandbox_type_ == sandbox::policy::SandboxType::kMediaFoundationCdm || #endif +#if defined(OS_MAC) + sandbox_type_ == sandbox::policy::SandboxType::kMirroring || +#endif sandbox_type_ == sandbox::policy::SandboxType::kUtility || sandbox_type_ == sandbox::policy::SandboxType::kNetwork || sandbox_type_ == sandbox::policy::SandboxType::kCdm ||
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 7e86720..fccd17ed 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -71,6 +71,7 @@ #include "third_party/blink/public/mojom/frame/blocked_navigation_types.mojom.h" #include "third_party/blink/public/mojom/frame/frame.mojom-forward.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h" +#include "third_party/blink/public/mojom/media/capture_handle_config.mojom.h" #include "third_party/blink/public/mojom/page/display_cutout.mojom.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h" #include "ui/accessibility/ax_mode.h"
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 586d043d..629f94c8 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -370,7 +370,7 @@ DCHECK(!idp_web_contents_); idp_web_contents_ = CreateIdpWebContents(); request_dialog_controller_->ShowAccountsDialog( - rp_web_contents, idp_web_contents_.get(), GURL(), accounts, + rp_web_contents, idp_web_contents_.get(), provider_, accounts, base::BindOnce(&FederatedAuthRequestImpl::OnAccountSelected, weak_ptr_factory_.GetWeakPtr())); return;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index f5c6782..a7851b3 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -354,6 +354,8 @@ {"COLRV1Fonts", blink::features::kCOLRV1Fonts}, {"CSSContainerQueries", blink::features::kCSSContainerQueries}, {"CompositeAfterPaint", blink::features::kCompositeAfterPaint}, + {"ComputePressure", blink::features::kComputePressure, + kSetOnlyIfOverridden}, {"CSSColorSchemeUARendering", features::kCSSColorSchemeUARendering}, {"DeclarativeShadowDOM", blink::features::kDeclarativeShadowDOM}, {"DocumentTransition", blink::features::kDocumentTransition},
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityState.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityState.java index ad1a717..be5b2ad 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityState.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityState.java
@@ -14,6 +14,7 @@ import android.os.Build; import android.os.Handler; import android.provider.Settings; +import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import org.chromium.base.ContextUtils; @@ -26,6 +27,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.WeakHashMap; /** * Provides utility methods relating to measuring accessibility state on the current platform (i.e. @@ -33,8 +36,23 @@ */ @JNINamespace("content") public class BrowserAccessibilityState { + /** + * An interface for classes that want to be notified whenever the accessibility + * state has changed, which can happen when accessibility services start or stop. + */ + public interface Listener { + public void onBrowserAccessibilityStateChanged(); + } + private static final String TAG = "Accessibility"; + // Analysis of the most popular accessibility services on Android suggests + // that any service that requests any of these three events is a screen reader + // or other complete assistive technology. If none of these events are requested, + // we can enable some optimizations. + private static final int SCREEN_READER_EVENT_TYPE_MASK = AccessibilityEvent.TYPE_VIEW_SELECTED + | AccessibilityEvent.TYPE_VIEW_SCROLLED | AccessibilityEvent.TYPE_ANNOUNCEMENT; + private static boolean sInitialized; // A bitmask containing the union of all event types, feedback types, flags, @@ -44,11 +62,21 @@ private static int sFlagsMask; private static int sCapabilitiesMask; + // Whether we determine that genuine assistive technology such as a screen reader + // is running, based on the information from running accessibility services. + private static boolean sScreenReader; + // The IDs of all running accessibility services. private static String[] sServiceIds; private static Handler sHandler; + // The set of listeners of BrowserAccessibilityState, implemented using + // a WeakHashSet behind the scenes so that listeners can be garbage-collected + // and will be automatically removed from this set. + private static Set<Listener> sListeners = + Collections.newSetFromMap(new WeakHashMap<Listener, Boolean>()); + // The number of milliseconds to wait before checking the set of running // accessibility services again, when we think it changed. Uses an exponential // back-off until it's greater than MAX_DELAY_MILLIS. @@ -56,6 +84,16 @@ private static final int MAX_DELAY_MILLIS = 60000; private static int sNextDelayMillis = MIN_DELAY_MILLIS; + public static void addListener(Listener listener) { + sListeners.add(listener); + } + + public static boolean screenReaderMode() { + if (!sInitialized) updateAccessibilityServices(); + + return sScreenReader; + } + private static class AnimatorDurationScaleObserver extends ContentObserver { public AnimatorDurationScaleObserver(Handler handler) { super(handler); @@ -164,6 +202,14 @@ getHandler().postDelayed(() -> { updateAccessibilityServices(); }, sNextDelayMillis); if (sNextDelayMillis < MAX_DELAY_MILLIS) sNextDelayMillis *= 2; } + + boolean oldScreenReader = sScreenReader; + sScreenReader = (0 != (sEventTypeMask & SCREEN_READER_EVENT_TYPE_MASK)); + if (sScreenReader != oldScreenReader) { + for (Listener listener : sListeners) { + listener.onBrowserAccessibilityStateChanged(); + } + } } static Handler getHandler() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java index 5d64827..e470001 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -72,7 +72,7 @@ @JNINamespace("content") public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider implements AccessibilityStateChangeListener, WebContentsAccessibility, WindowEventObserver, - UserData { + UserData, BrowserAccessibilityState.Listener { // The following constants have been hard coded so we can support actions newer than our // minimum SDK without having to break methods into a series of subclasses. // Constants defined by AccessibilityNodeInfo per SDK @@ -248,6 +248,8 @@ mDelegate.setOnScrollPositionChangedCallback( () -> handleScrollPositionChanged(mAccessibilityFocusId)); + BrowserAccessibilityState.addListener(this); + // Define our delays on a per event type basis. Map<Integer, Integer> eventThrottleDelays = new HashMap<Integer, Integer>(); eventThrottleDelays.put( @@ -469,8 +471,9 @@ onNativeInit(); } if (!isEnabled()) { + boolean screenReaderMode = BrowserAccessibilityState.screenReaderMode(); WebContentsAccessibilityImplJni.get().enable( - mNativeObj, WebContentsAccessibilityImpl.this); + mNativeObj, WebContentsAccessibilityImpl.this, screenReaderMode); return null; } return this; @@ -566,12 +569,25 @@ } // AccessibilityStateChangeListener + // TODO(dmazzoni): have BrowserAccessibilityState monitor this and merge + // into BrowserAccessibilityStateListener. @Override public void onAccessibilityStateChanged(boolean enabled) { setState(enabled); } + // BrowserAccessibilityStateListener + + @Override + public void onBrowserAccessibilityStateChanged() { + if (!isAccessibilityEnabled()) return; + + boolean screenReaderMode = BrowserAccessibilityState.screenReaderMode(); + WebContentsAccessibilityImplJni.get().setAXMode( + mNativeObj, WebContentsAccessibilityImpl.this, screenReaderMode); + } + // WebContentsAccessibility @Override @@ -2096,8 +2112,10 @@ WebContentsAccessibilityImpl caller, int id); boolean isEnabled( long nativeWebContentsAccessibilityAndroid, WebContentsAccessibilityImpl caller); - void enable( - long nativeWebContentsAccessibilityAndroid, WebContentsAccessibilityImpl caller); + void enable(long nativeWebContentsAccessibilityAndroid, WebContentsAccessibilityImpl caller, + boolean screenReaderMode); + void setAXMode(long nativeWebContentsAccessibilityAndroid, + WebContentsAccessibilityImpl caller, boolean screenReaderMode); boolean areInlineTextBoxesLoaded(long nativeWebContentsAccessibilityAndroid, WebContentsAccessibilityImpl caller, int id); void loadInlineTextBoxes(long nativeWebContentsAccessibilityAndroid,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 0b1a60b..b482481 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -1307,8 +1307,7 @@ // Allows the embedder to register per-scheme URLLoaderFactory // implementations to handle service worker main/imported script requests // initiated by the browser process for schemes not handled by the Network - // Service. Only called for service worker update check when - // ServiceWorkerImportedScriptUpdateCheck is enabled. + // Service. Only called for service worker update check. // The resulting |factories| must be used only by the browser process. The // caller must not send any of |factories| to any other process. virtual void RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc index 375c3ed7..0c3ca3e 100644 --- a/content/public/browser/site_isolation_policy.cc +++ b/content/public/browser/site_isolation_policy.cc
@@ -181,6 +181,15 @@ } // static +bool SiteIsolationPolicy::ShouldPersistIsolatedCOOPSites() { + if (!IsSiteIsolationForCOOPEnabled()) + return false; + + return features::kSiteIsolationForCrossOriginOpenerPolicyShouldPersistParam + .Get(); +} + +// static std::string SiteIsolationPolicy::GetIsolatedOriginsFromCommandLine() { std::string cmdline_arg = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
diff --git a/content/public/browser/site_isolation_policy.h b/content/public/browser/site_isolation_policy.h index 9c06f9b..e201e25 100644 --- a/content/public/browser/site_isolation_policy.h +++ b/content/public/browser/site_isolation_policy.h
@@ -60,6 +60,10 @@ // heuristics for turning on site isolation. static bool IsSiteIsolationForCOOPEnabled(); + // Return true if sites that were isolated due to COOP headers should be + // persisted across restarts. + static bool ShouldPersistIsolatedCOOPSites(); + // Applies isolated origins from all available sources, including the // command-line switch, field trials, enterprise policy, and the embedder. // See also AreIsolatedOriginsEnabled. These origins apply globally to the
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 6428522..1fd0d64 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -33,7 +33,7 @@ #include "third_party/blink/public/mojom/favicon/favicon_url.mojom-forward.h" #include "third_party/blink/public/mojom/frame/find_in_page.mojom-forward.h" #include "third_party/blink/public/mojom/input/pointer_lock_result.mojom.h" -#include "third_party/blink/public/mojom/mediastream/media_devices.mojom.h" +#include "third_party/blink/public/mojom/media/capture_handle_config.mojom-forward.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_mode.h"
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index c87466e..16ff713 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -28,7 +28,7 @@ #include "third_party/blink/public/mojom/devtools/console_message.mojom.h" #include "third_party/blink/public/mojom/favicon/favicon_url.mojom-forward.h" #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-forward.h" -#include "third_party/blink/public/mojom/media/capture_handle_config.mojom.h" +#include "third_party/blink/public/mojom/media/capture_handle_config.mojom-forward.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h"
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 3164947..6df11ea 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -723,6 +723,18 @@ const base::Feature kSiteIsolationForCrossOriginOpenerPolicy{ "SiteIsolationForCrossOriginOpenerPolicy", base::FEATURE_DISABLED_BY_DEFAULT}; +// This feature param (true by default) controls whether sites are persisted +// across restarts. +const base::FeatureParam<bool> + kSiteIsolationForCrossOriginOpenerPolicyShouldPersistParam{ + &kSiteIsolationForCrossOriginOpenerPolicy, + "should_persist_across_restarts", true}; +// This feature param controls the maximum size of stored sites. Only used +// when persistence is also enabled. +const base::FeatureParam<int> + kSiteIsolationForCrossOriginOpenerPolicyMaxSitesParam{ + &kSiteIsolationForCrossOriginOpenerPolicy, "stored_sites_max_size", + 100}; // Controls whether SpareRenderProcessHostManager tries to always have a warm // spare renderer process around for the most recently requested BrowserContext.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 2450380..3e88614 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -165,6 +165,10 @@ CONTENT_EXPORT extern const base::Feature kSignedHTTPExchangePingValidity; CONTENT_EXPORT extern const base::Feature kSiteIsolationForCrossOriginOpenerPolicy; +CONTENT_EXPORT extern const base::FeatureParam<bool> + kSiteIsolationForCrossOriginOpenerPolicyShouldPersistParam; +CONTENT_EXPORT extern const base::FeatureParam<int> + kSiteIsolationForCrossOriginOpenerPolicyMaxSitesParam; CONTENT_EXPORT extern const base::Feature kSkipEarlyCommitPendingForCrashedFrame; CONTENT_EXPORT extern const base::Feature kWebOTP;
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index f411c6a..83f5ed9c 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -682,13 +682,13 @@ discardable_shared_memory_manager.reset(); } + // Like in BrowserMainLoop::ShutdownThreadsAndCleanUp(), allow IO during main + // thread tear down. + base::ThreadRestrictions::SetIOAllowed(true); + base::PostTaskAndroid::SignalNativeSchedulerShutdownForTesting(); BrowserTaskExecutor::Shutdown(); - // Normally the BrowserMainLoop does this during shutdown but on Android we - // don't go through shutdown, so this doesn't happen there. We do need it - // for the test harness to be able to delete temp dirs. - base::ThreadRestrictions::SetIOAllowed(true); #else // defined(OS_ANDROID) auto ui_task = std::make_unique<base::OnceClosure>(base::BindOnce( &BrowserTestBase::ProxyRunTestOnMainThreadLoop, base::Unretained(this))); @@ -697,6 +697,7 @@ created_main_parts_closure.release(); EXPECT_EQ(expected_exit_code_, ContentMain(*GetContentMainParams())); #endif // defined(OS_ANDROID) + TearDownInProcessBrowserTestFixture(); }
diff --git a/content/services/auction_worklet/BUILD.gn b/content/services/auction_worklet/BUILD.gn index 63275a4..0f89dae 100644 --- a/content/services/auction_worklet/BUILD.gn +++ b/content/services/auction_worklet/BUILD.gn
@@ -8,8 +8,6 @@ sources = [ "auction_downloader.cc", "auction_downloader.h", - "auction_runner.cc", - "auction_runner.h", "auction_v8_helper.cc", "auction_v8_helper.h", "auction_worklet_service_impl.cc", @@ -50,7 +48,6 @@ sources = [ "auction_downloader_unittest.cc", - "auction_runner_unittest.cc", "auction_v8_helper_unittest.cc", "bidder_worklet_unittest.cc", "seller_worklet_unittest.cc", @@ -70,6 +67,7 @@ "//services/service_manager/public/cpp/test:test_support", "//testing/gmock", "//testing/gtest", + "//v8", ] if (v8_use_external_startup_data) {
diff --git a/content/services/auction_worklet/auction_runner.cc b/content/services/auction_worklet/auction_runner.cc deleted file mode 100644 index 85cdc074..0000000 --- a/content/services/auction_worklet/auction_runner.cc +++ /dev/null
@@ -1,260 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/services/auction_worklet/auction_runner.h" - -#include "base/callback_forward.h" -#include "base/time/time.h" -#include "content/services/auction_worklet/auction_v8_helper.h" -#include "content/services/auction_worklet/bidder_worklet.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" -#include "content/services/auction_worklet/seller_worklet.h" -#include "services/network/public/mojom/url_loader_factory.mojom-forward.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" -#include "url/gurl.h" - -namespace auction_worklet { - -AuctionRunner::BidState::BidState() = default; -AuctionRunner::BidState::~BidState() = default; -AuctionRunner::BidState::BidState(BidState&&) = default; - -void AuctionRunner::CreateAndStart( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback) { - AuctionRunner* instance = new AuctionRunner( - std::move(url_loader_factory), std::move(auction_config), - std::move(bidders), std::move(browser_signals), std::move(callback)); - instance->StartBidding(); -} - -AuctionRunner::AuctionRunner( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback) - : url_loader_factory_(std::move(url_loader_factory)), - auction_config_(std::move(auction_config)), - bidders_(std::move(bidders)), - browser_signals_(std::move(browser_signals)), - callback_(std::move(callback)) {} - -AuctionRunner::~AuctionRunner() { - DCHECK(callback_.is_null()); -} - -void AuctionRunner::StartBidding() { - outstanding_bids_ = bidders_.size(); - bid_states_.resize(outstanding_bids_); - - for (int bid_index = 0; bid_index < outstanding_bids_; ++bid_index) { - const mojom::BiddingInterestGroupPtr& bidder = bidders_[bid_index]; - BidState* bid_state = &bid_states_[bid_index]; - bid_state->bidder = bidder.get(); - // TODO(morlovich): Straight skip if URL is missing. - bid_state->bidder_worklet = std::make_unique<BidderWorklet>( - &auction_v8_helper_, url_loader_factory_.get(), bidder->Clone(), - auction_config_->auction_signals, PerBuyerSignals(bid_state), - browser_signals_->top_frame_origin, browser_signals_->seller, - auction_start_time_, - base::BindOnce(&AuctionRunner::OnGenerateBidComplete, - base::Unretained(this), bid_state)); - } - - // Also initiate the script fetch for the seller script. - seller_worklet_ = std::make_unique<SellerWorklet>( - &auction_v8_helper_, url_loader_factory_.get(), - auction_config_->decision_logic_url, - base::BindOnce(&AuctionRunner::OnSellerWorkletLoaded, - base::Unretained(this))); -} - -void AuctionRunner::OnGenerateBidComplete( - BidState* state, - absl::optional<BidderWorklet::Bid> bid, - const std::vector<std::string>& errors) { - DCHECK(!state->bid_generate_complete); - DCHECK_GT(outstanding_bids_, 0); - - --outstanding_bids_; - - errors_.insert(errors_.end(), errors.begin(), errors.end()); - state->bid_generate_complete = true; - state->bid_result = std::move(bid); - - if (ReadyToScore()) - ScoreOne(); -} - -void AuctionRunner::OnSellerWorkletLoaded( - bool load_result, - const std::vector<std::string>& errors) { - errors_.insert(errors_.end(), errors.begin(), errors.end()); - - if (load_result) { - seller_loaded_ = true; - if (ReadyToScore()) - ScoreOne(); - } else { - // Failed to load the seller/auction script --- nothing useful can be done, - // so abort, possibly cancelling other fetches, so we don't waste time. - FailAuction(); - } -} - -void AuctionRunner::ScoreOne() { - size_t num_bidders = bid_states_.size(); - - // Find next valid bid to score, if any. - while (seller_considering_ < num_bidders) { - BidState* bid_state = &bid_states_[seller_considering_]; - - // Skip over bidders that produced no valid bid. - if (!bid_state->bid_result) { - ++seller_considering_; - continue; - } - - ScoreBid(bid_state); - return; - } - - DCHECK_EQ(seller_considering_, num_bidders); - CompleteAuction(); -} - -void AuctionRunner::ScoreBid(const BidState* state) { - seller_worklet_->ScoreAd( - state->bid_result->ad, state->bid_result->bid, *auction_config_, - browser_signals_->top_frame_origin, state->bidder->group->owner, - AdRenderFingerprint(state), - state->bid_result->bid_duration.InMilliseconds(), - base::BindOnce(&AuctionRunner::OnBidScored, base::Unretained(this))); -} - -void AuctionRunner::OnBidScored(double score, - const std::vector<std::string>& errors) { - bid_states_[seller_considering_].seller_score = score; - errors_.insert(errors_.end(), errors.begin(), errors.end()); - ++seller_considering_; - ScoreOne(); -} - -std::string AuctionRunner::AdRenderFingerprint(const BidState* state) { - // TODO(morlovich): "Eventually this fingerprint can be a hash of the ad web - // bundle, but while rendering still uses the network, it should just be a - // hash of the rendering URL." - // - return "#####"; -} - -absl::optional<std::string> AuctionRunner::PerBuyerSignals( - const BidState* state) { - if (auction_config_->per_buyer_signals.has_value()) { - auto it = auction_config_->per_buyer_signals.value().find( - state->bidder->group->owner); - if (it != auction_config_->per_buyer_signals.value().end()) - return it->second; - } - return absl::nullopt; -} - -void AuctionRunner::CompleteAuction() { - double best_bid_score = 0.0; - const BidState* best_bid = nullptr; - // TODO(morlovich): What if there is a tie? - for (const BidState& bid_state : bid_states_) { - if (bid_state.seller_score > best_bid_score) { - best_bid_score = bid_state.seller_score; - best_bid = &bid_state; - } - } - - if (best_bid) { - // Will eventually send a report to the seller and clean up `this`. - ReportSellerResult(best_bid); - } else { - FailAuction(); - } -} - -void AuctionRunner::ReportSellerResult(const BidState* best_bid) { - DCHECK(best_bid->bid_result); - DCHECK_GT(best_bid->seller_score, 0); - seller_worklet_->ReportResult( - *auction_config_, browser_signals_->top_frame_origin, - best_bid->bidder->group->owner, best_bid->bid_result->render_url, - AdRenderFingerprint(best_bid), best_bid->bid_result->bid, - best_bid->seller_score, - base::BindOnce(&AuctionRunner::OnReportSellerResultComplete, - base::Unretained(this), best_bid)); -} - -void AuctionRunner::OnReportSellerResultComplete( - const BidState* best_bid, - const absl::optional<std::string>& signals_for_winner, - const absl::optional<GURL>& seller_report_url, - const std::vector<std::string>& errors) { - signals_for_winner_ = signals_for_winner; - seller_report_url_ = seller_report_url; - errors_.insert(errors_.end(), errors.begin(), errors.end()); - - ReportBidWin(best_bid); -} - -void AuctionRunner::ReportBidWin(const BidState* best_bid) { - CHECK(best_bid->bid_result); - std::string signals_for_winner_arg; - // TODO(mmenke): It's unclear what should happen here if `signals_for_winner_` - // is null. As-is, an empty string will result in the BidderWorklet's - // ReportWin() method failing, since it's not valid JSON. - if (signals_for_winner_) - signals_for_winner_arg = *signals_for_winner_; - best_bid->bidder_worklet->ReportWin( - signals_for_winner_arg, best_bid->bid_result->render_url, - AdRenderFingerprint(best_bid), best_bid->bid_result->bid, - base::BindOnce(&AuctionRunner::OnReportBidWinComplete, - base::Unretained(this), best_bid)); -} - -void AuctionRunner::OnReportBidWinComplete( - const BidState* best_bid, - const absl::optional<GURL>& bidder_report_url, - const std::vector<std::string>& errors) { - bidder_report_url_ = bidder_report_url; - errors_.insert(errors_.end(), errors.begin(), errors.end()); - ReportSuccess(best_bid); -} - -void AuctionRunner::FailAuction() { - std::move(callback_).Run( - GURL(), url::Origin(), std::string(), - mojom::WinningBidderReport::New(false /* success */, GURL()), - mojom::SellerReport::New(false /* success */, "", GURL()), errors_); - delete this; -} - -void AuctionRunner::ReportSuccess(const BidState* state) { - DCHECK(state->bid_result); - - std::move(callback_).Run( - state->bid_result->render_url, state->bidder->group->owner, - state->bidder->group->name, - mojom::WinningBidderReport::New( - bidder_report_url_.has_value(), - bidder_report_url_.has_value() ? *bidder_report_url_ : GURL()), - mojom::SellerReport::New( - signals_for_winner_.has_value(), - "<TODO: Remove this. Currently ignored>", - seller_report_url_.has_value() ? *seller_report_url_ : GURL()), - errors_); - delete this; -} - -} // namespace auction_worklet
diff --git a/content/services/auction_worklet/auction_runner.h b/content/services/auction_worklet/auction_runner.h deleted file mode 100644 index d164bda..0000000 --- a/content/services/auction_worklet/auction_runner.h +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_RUNNER_H_ -#define CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_RUNNER_H_ - -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/logging.h" -#include "base/time/time.h" -#include "content/services/auction_worklet/auction_v8_helper.h" -#include "content/services/auction_worklet/bidder_worklet.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" -#include "content/services/auction_worklet/seller_worklet.h" -#include "services/network/public/mojom/url_loader_factory.mojom-forward.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" -#include "url/gurl.h" - -namespace auction_worklet { - -// An AuctionRunner loads and runs the bidder and seller worklets, along with -// their reporting phases and produces the result via a callback. -// -// This is a self-owned object. It destroys itself after invoking the callback -// passed to CreateAndStart. -// -// At present it initiates all fetches in parallel, running all bidder scripts -// once they and any trusted signals they need are ready, then when all bids are -// in runs all the scoring, and finally the reporting worklets. -// -// TODO(morlovich): There is no need to wait for all bidders to finish to start -// scoring. -class AuctionRunner { - public: - explicit AuctionRunner(const AuctionRunner&) = delete; - AuctionRunner& operator=(const AuctionRunner&) = delete; - - static void CreateAndStart( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback); - - private: - struct BidState { - BidState(); - BidState(BidState&&); - ~BidState(); - - mojom::BiddingInterestGroup* bidder = nullptr; - - // true if the generateBid() callback passed to the BidderWorklet's - // constructor has been invoked. This may indicated either successful - // generation of a bid, or failure to load or run the script. - bool bid_generate_complete = false; - - std::unique_ptr<BidderWorklet> bidder_worklet; - absl::optional<BidderWorklet::Bid> bid_result; - double seller_score = 0; - }; - - AuctionRunner( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback); - ~AuctionRunner(); - - void StartBidding(); - void OnGenerateBidComplete(BidState* state, - absl::optional<BidderWorklet::Bid> bid, - const std::vector<std::string>& errors); - - // True if all bid results and the seller script load are complete. - bool ReadyToScore() const { return outstanding_bids_ == 0 && seller_loaded_; } - void OnSellerWorkletLoaded(bool load_result, - const std::vector<std::string>& errors); - - // Calls into the seller to asynchronously each of outstanding bids, in - // series. Once there are no outstanding bids, proceeds to selecting the - // winner and running the Worklets reporting methods. - // - // Destroys `this` (indirectly), upon wrapping up the auction if all bids have - // been scored (including if there were none). - void ScoreOne(); - void ScoreBid(const BidState* state); - // Callback from ScoreBid(). - void OnBidScored(double score, const std::vector<std::string>& errors); - - std::string AdRenderFingerprint(const BidState* state); - absl::optional<std::string> PerBuyerSignals(const BidState* state); - - void CompleteAuction(); // Indirectly deletes `this`, if there's no winner. - - // Sequence of asynchronous methods to call into the bidder/seller results to - // report a a win, Will ultimately invoke ReportSuccess(), which will delete - // the auction. - void ReportSellerResult(const BidState* state); - void OnReportSellerResultComplete( - const BidState* best_bid, - const absl::optional<std::string>& signals_for_winner, - const absl::optional<GURL>& seller_report_url, - const std::vector<std::string>& errors); - void ReportBidWin(const BidState* state); - void OnReportBidWinComplete(const BidState* best_bid, - const absl::optional<GURL>& bidder_report_url, - const std::vector<std::string>& error_msgs); - - // Destroys `this`. - void FailAuction(); - - // Destroys `this`. - void ReportSuccess(const BidState* state); - - // `auction_v8_helper_` needs to be before the worklets, since they refer to - // it. - AuctionV8Helper auction_v8_helper_; - - // Configuration. - mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_; - blink::mojom::AuctionAdConfigPtr auction_config_; - std::vector<mojom::BiddingInterestGroupPtr> bidders_; - mojom::BrowserSignalsPtr browser_signals_; - mojom::AuctionWorkletService::RunAuctionCallback callback_; - - // State for the bidding phase. - int outstanding_bids_; // number of bids for which we're waiting on a fetch. - std::vector<BidState> bid_states_; // parallel to `bidders_`. - // The time the auction started. Use a single base time for all Worklets, to - // present a more consistent view of the universe. - const base::Time auction_start_time_ = base::Time::Now(); - - // State for the scoring phase. - std::unique_ptr<SellerWorklet> seller_worklet_; - - // This is true if the seller script has been loaded successfully --- if the - // load failed, the entire process is aborted since there is nothing useful - // that can be done. - bool seller_loaded_ = false; - size_t seller_considering_ = 0; - - // Seller script reportResult() results. - absl::optional<std::string> signals_for_winner_; - absl::optional<GURL> seller_report_url_; - - // Bidder script reportWin() results. - absl::optional<GURL> bidder_report_url_; - - // All errors reported by worklets thus far. - std::vector<std::string> errors_; -}; - -} // namespace auction_worklet - -#endif // CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_RUNNER_H_
diff --git a/content/services/auction_worklet/auction_runner_unittest.cc b/content/services/auction_worklet/auction_runner_unittest.cc deleted file mode 100644 index cb62811..0000000 --- a/content/services/auction_worklet/auction_runner_unittest.cc +++ /dev/null
@@ -1,750 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/services/auction_worklet/auction_runner.h" - -#include <vector> - -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "base/test/bind.h" -#include "base/test/task_environment.h" -#include "base/time/time.h" -#include "content/services/auction_worklet/worklet_test_util.h" -#include "net/http/http_status_code.h" -#include "services/network/test/test_url_loader_factory.h" -#include "testing/gmock/include/gmock/gmock-matchers.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace auction_worklet { -namespace { - -std::string MakeBidScript(const std::string& bid, - const std::string& render_url, - const url::Origin& interest_group_owner, - const std::string& interest_group_name, - bool has_signals, - const std::string& signal_key, - const std::string& signal_val) { - // TODO(morlovich): Use JsReplace. - constexpr char kBidScript[] = R"( - const bid = %s; - const renderUrl = "%s"; - const interestGroupOwner = "%s"; - const interestGroupName = "%s"; - const hasSignals = %s; - - function generateBid(interestGroup, auctionSignals, perBuyerSignals, - trustedBiddingSignals, browserSignals) { - var result = {ad: {bidKey: "data for " + bid, - groupName: interestGroupName}, - bid: bid, render: renderUrl}; - if (interestGroup.name !== interestGroupName) - throw new Error("wrong interestGroupName"); - if (interestGroup.owner !== interestGroupOwner) - throw new Error("wrong interestGroupOwner"); - if (perBuyerSignals.signalsFor !== interestGroupName) - throw new Error("wrong perBuyerSignals"); - if (!auctionSignals.isAuctionSignals) - throw new Error("wrong auctionSignals"); - if (hasSignals) { - if ('extra' in trustedBiddingSignals) - throw new Error("why extra?"); - if (trustedBiddingSignals["%s"] !== "%s") - throw new Error("wrong signals"); - } else if (trustedBiddingSignals !== null) { - throw new Error("Expected null trustedBiddingSignals"); - } - if (browserSignals.topWindowHostname !== 'publisher1.com') - throw new Error("wrong topWindowHostname"); - if (browserSignals.seller != 'https://adstuff.publisher1.com') - throw new Error("wrong seller"); - if (browserSignals.joinCount !== 3) - throw new Error("joinCount") - if (browserSignals.bidCount !== 5) - throw new Error("bidCount"); - if (browserSignals.prevWins.length !== 3) - throw new Error("prevWins"); - for (let i = 0; i < browserSignals.prevWins.length; ++i) { - if (!(browserSignals.prevWins[i] instanceof Array)) - throw new Error("prevWins entry not an array"); - if (typeof browserSignals.prevWins[i][0] != "number") - throw new Error("Not a Number in prevWin?"); - if (browserSignals.prevWins[i][1].winner !== -i) - throw new Error("prevWin MD not what passed in"); - } - return result; - } - - function reportWin(auctionSignals, perBuyerSignals, sellerSignals, - browserSignals) { - if (!auctionSignals.isAuctionSignals) - throw new Error("wrong auctionSignals"); - if (perBuyerSignals.signalsFor !== interestGroupName) - throw new Error("wrong perBuyerSignals"); - - // sellerSignals in these tests is just sellers' browserSignals, since - // that's what reportResult passes through. - if (sellerSignals.topWindowHostname !== 'publisher1.com') - throw new Error("wrong topWindowHostname"); - if (sellerSignals.interestGroupOwner !== interestGroupOwner) - throw new Error("wrong interestGroupOwner"); - if (sellerSignals.renderUrl !== renderUrl) - throw new Error("wrong renderUrl"); - if (sellerSignals.bid !== bid) - throw new Error("wrong bid"); - if (sellerSignals.desirability !== (bid * 2)) - throw new Error("wrong desirability"); - - if (browserSignals.topWindowHostname !== 'publisher1.com') - throw new Error("wrong browserSignals.topWindowHostname"); - if ("desirability" in browserSignals) - throw new Error("why is desirability here?"); - if (browserSignals.interestGroupName !== interestGroupName) - throw new Error("wrong browserSignals.interestGroupName"); - if (browserSignals.interestGroupOwner !== interestGroupOwner) - throw new Error("wrong browserSignals.interestGroupOwner"); - - if (browserSignals.renderUrl !== renderUrl) - throw new Error("wrong browserSignals.renderUrl"); - if (browserSignals.bid !== bid) - throw new Error("wrong browserSignals.bid"); - - sendReportTo("https://buyer-reporting.example.com"); - } - )"; - return base::StringPrintf( - kBidScript, bid.c_str(), render_url.c_str(), - interest_group_owner.Serialize().c_str(), interest_group_name.c_str(), - has_signals ? "true" : "false", signal_key.c_str(), signal_val.c_str()); -} - -// This can be appended to the standard script to override the function. -constexpr char kReportWinNoUrl[] = R"( - function reportWin(auctionSignals, perBuyerSignals, sellerSignals, - browserSignals) { - } -)"; - -constexpr char kCheckingAuctionScript[] = R"( - function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals, - browserSignals) { - if (adMetadata.bidKey !== ("data for " + bid)) { - throw new Error("wrong data for bid:" + - JSON.stringify(adMetadata) + "/" + bid); - } - if (auctionConfig.decisionLogicUrl - !== "https://adstuff.publisher1.com/auction.js") { - throw new Error("wrong auctionConfig"); - } - if (auctionConfig.perBuyerSignals['adplatform.com'].signalsFor - !== 'Ad Platform') { - throw new Error("Wrong perBuyerSignals in auctionConfig"); - } - if (!auctionConfig.sellerSignals.isSellerSignals) - throw new Error("Wrong sellerSignals"); - if (browserSignals.topWindowHostname !== 'publisher1.com') - throw new Error("wrong topWindowHostname"); - if ("joinCount" in browserSignals) - throw new Error("wrong kind of browser signals"); - if (browserSignals.adRenderFingerprint !== "#####") - throw new Error("wrong adRenderFingerprint"); - if (typeof browserSignals.biddingDurationMsec !== "number") - throw new Error("biddingDurationMsec is not a number. huh"); - if (browserSignals.biddingDurationMsec < 0) - throw new Error("biddingDurationMsec should be non-negative."); - - return bid * 2; - } -)"; - -constexpr char kReportResultScript[] = R"( - function reportResult(auctionConfig, browserSignals) { - if (auctionConfig.decisionLogicUrl - !== "https://adstuff.publisher1.com/auction.js") { - throw new Error("wrong auctionConfig"); - } - if (browserSignals.topWindowHostname !== 'publisher1.com') - throw new Error("wrong topWindowHostname"); - sendReportTo("https://reporting.example.com"); - return browserSignals; - } -)"; - -constexpr char kReportResultScriptNoUrl[] = R"( - function reportResult(auctionConfig, browserSignals) { - return browserSignals; - } -)"; - -std::string MakeAuctionScript() { - return std::string(kCheckingAuctionScript) + kReportResultScript; -} - -std::string MakeAuctionScriptNoReportUrl() { - return std::string(kCheckingAuctionScript) + kReportResultScriptNoUrl; -} - -const char kAuctionScriptRejects2[] = R"( - function scoreAd(adMetadata, bid, auctionConfig, browserSignals) { - if (bid === 2) - return -1; - return bid + 1; - } -)"; - -std::string MakeAuctionScriptReject2() { - return std::string(kAuctionScriptRejects2) + kReportResultScript; -} - -class AuctionRunnerTest : public testing::Test { - protected: - struct Result { - GURL ad_url; - url::Origin interest_group_owner; - std::string interest_group_name; - mojom::WinningBidderReportPtr bidder_report; - mojom::SellerReportPtr seller_report; - std::vector<std::string> errors; - }; - - Result RunAuctionAndWait(const GURL& seller_decision_logic_url, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - const std::string& auction_signals_json, - mojom::BrowserSignalsPtr browser_signals) { - mojo::Receiver<network::mojom::URLLoaderFactory> factory_receiver{ - &url_loader_factory_}; - - blink::mojom::AuctionAdConfigPtr auction_config = - blink::mojom::AuctionAdConfig::New(); - auction_config->seller = url::Origin::Create(seller_decision_logic_url); - auction_config->decision_logic_url = seller_decision_logic_url; - auction_config->interest_group_buyers = - blink::mojom::InterestGroupBuyers::NewAllBuyers( - blink::mojom::AllBuyers::New()); - auction_config->auction_signals = auction_signals_json; - auction_config->seller_signals = R"({"isSellerSignals": true})"; - - base::flat_map<url::Origin, std::string> per_buyer_signals; - per_buyer_signals[kBidder1] = R"({"signalsFor": ")" + kBidder1Name + "\"}"; - per_buyer_signals[kBidder2] = R"({"signalsFor": ")" + kBidder2Name + "\"}"; - auction_config->per_buyer_signals = std::move(per_buyer_signals); - - base::RunLoop run_loop; - Result result; - AuctionRunner::CreateAndStart( - factory_receiver.BindNewPipeAndPassRemote(), std::move(auction_config), - std::move(bidders), std::move(browser_signals), - base::BindLambdaForTesting([&](const GURL& ad_url, - const url::Origin& interest_group_owner, - const std::string& interest_group_name, - mojom::WinningBidderReportPtr bid_report, - mojom::SellerReportPtr seller_report, - const std::vector<std::string>& errors) { - result.ad_url = ad_url; - result.interest_group_owner = interest_group_owner; - result.interest_group_name = interest_group_name; - result.bidder_report = std::move(bid_report); - result.seller_report = std::move(seller_report); - result.errors = errors; - run_loop.Quit(); - })); - run_loop.Run(); - return result; - } - - mojom::BiddingInterestGroupPtr MakeInterestGroup( - const url::Origin& owner, - const std::string& name, - const GURL& bidding_url, - const absl::optional<GURL>& trusted_bidding_signals_url, - const std::vector<std::string>& trusted_bidding_signals_keys, - const GURL& ad_url) { - std::vector<blink::mojom::InterestGroupAdPtr> ads; - ads.push_back( - blink::mojom::InterestGroupAd::New(ad_url, R"({"ads": true})")); - - std::vector<mojom::PreviousWinPtr> previous_wins; - previous_wins.push_back( - mojom::PreviousWin::New(base::Time::Now(), R"({"winner": 0})")); - previous_wins.push_back( - mojom::PreviousWin::New(base::Time::Now(), R"({"winner": -1})")); - previous_wins.push_back( - mojom::PreviousWin::New(base::Time::Now(), R"({"winner": -2})")); - - return mojom::BiddingInterestGroup::New( - blink::mojom::InterestGroup::New( - base::Time::Max(), owner, name, bidding_url, - GURL() /* update_url */, trusted_bidding_signals_url, - trusted_bidding_signals_keys, absl::nullopt, std::move(ads)), - mojom::BiddingBrowserSignals::New(3, 5, std::move(previous_wins))); - } - - Result RunStandardAuction() { - std::vector<mojom::BiddingInterestGroupPtr> bidders; - bidders.push_back(MakeInterestGroup(kBidder1, kBidder1Name, kBidder1Url, - kTrustedSignalsUrl, {"k1", "k2"}, - GURL("https://ad1.com"))); - bidders.push_back(MakeInterestGroup(kBidder2, kBidder2Name, kBidder2Url, - kTrustedSignalsUrl, {"l1", "l2"}, - GURL("https://ad2.com"))); - - return RunAuctionAndWait( - kSellerUrl, std::move(bidders), - R"({"isAuctionSignals": true})", /* auction_signals_json */ - mojom::BrowserSignals::New( - url::Origin::Create(GURL("https://publisher1.com")), - url::Origin::Create(kSellerUrl))); - } - - const GURL kSellerUrl{"https://adstuff.publisher1.com/auction.js"}; - const GURL kBidder1Url{"https://adplatform.com/offers.js"}; - const url::Origin kBidder1 = - url::Origin::Create(GURL("https://adplatform.com")); - const std::string kBidder1Name{"Ad Platform"}; - const GURL kBidder2Url{"https://anotheradthing.com/bids.js"}; - const url::Origin kBidder2 = - url::Origin::Create(GURL("https://anotheradthing.com")); - const std::string kBidder2Name{"Another Ad Thing"}; - - const GURL kTrustedSignalsUrl{"https://trustedsignaller.org/signals"}; - - base::test::TaskEnvironment task_environment_; - network::TestURLLoaderFactory url_loader_factory_; -}; - -// An auction with two successful bids. -TEST_F(AuctionRunnerTest, Basic) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a")); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b")); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT(res.errors, testing::ElementsAre()); -} - -// An auction where one bid is successful, another's script 404s. -TEST_F(AuctionRunnerTest, OneBidOne404) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a")); - url_loader_factory_.AddResponse(kBidder2Url.spec(), "", net::HTTP_NOT_FOUND); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT( - res.errors, - testing::ElementsAre("Failed to load https://anotheradthing.com/bids.js " - "HTTP status = 404 Not Found.")); -} - -// An auction where one bid is successful, another's script does not provide a -// bidding function. -TEST_F(AuctionRunnerTest, OneBidOneNotMade) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a")); - - // The auction script doesn't make any bids. - AddJavascriptResponse(&url_loader_factory_, kBidder2Url, MakeAuctionScript()); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT(res.errors, - testing::ElementsAre("https://anotheradthing.com/bids.js " - "`generateBid` is not a function.")); -} - -// An auction where no bidding scripts load successfully. -TEST_F(AuctionRunnerTest, NoBids) { - url_loader_factory_.AddResponse(kBidder1Url.spec(), "", net::HTTP_NOT_FOUND); - url_loader_factory_.AddResponse(kBidder2Url.spec(), "", net::HTTP_NOT_FOUND); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2":"b", "extra":"c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra":"c"})"); - - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_FALSE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - EXPECT_THAT( - res.errors, - testing::ElementsAre("Failed to load https://adplatform.com/offers.js " - "HTTP status = 404 Not Found.", - "Failed to load https://anotheradthing.com/bids.js " - "HTTP status = 404 Not Found.")); -} - -// An auction where none of the bidding scripts has a valid bidding function. -TEST_F(AuctionRunnerTest, NoBidMadeByScript) { - // MakeAuctionScript() is a valid script that doesn't have a bidding function. - AddJavascriptResponse(&url_loader_factory_, kBidder1Url, MakeAuctionScript()); - AddJavascriptResponse(&url_loader_factory_, kBidder2Url, MakeAuctionScript()); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2":"b", "extra":"c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra":"c"})"); - - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_FALSE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - EXPECT_THAT( - res.errors, - testing::ElementsAre( - "https://adplatform.com/offers.js `generateBid` is not a function.", - "https://anotheradthing.com/bids.js `generateBid` is not a " - "function.")); -} - -// An auction where the seller script doesn't have a scoring function. -TEST_F(AuctionRunnerTest, SellerRejectsAll) { - std::string bid_script1 = - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a"); - AddJavascriptResponse(&url_loader_factory_, kBidder1Url, bid_script1); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b")); - - // No seller scoring function in a bid script. - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, bid_script1); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2":"b", "extra":"c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra":"c"})"); - - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_FALSE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - EXPECT_THAT(res.errors, - testing::ElementsAre("https://adstuff.publisher1.com/auction.js " - "`scoreAd` is not a function.", - "https://adstuff.publisher1.com/auction.js " - "`scoreAd` is not a function.")); -} - -// An auction where seller rejects one bid when scoring. -TEST_F(AuctionRunnerTest, SellerRejectsOne) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a")); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b")); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, - MakeAuctionScriptReject2()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad1.com/", res.ad_url.spec()); - EXPECT_EQ("https://adplatform.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Ad Platform", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); -} - -// An auction where the seller script fails to load. -TEST_F(AuctionRunnerTest, NoSellerScript) { - // Tests to make sure that if seller script fails the other fetches are - // cancelled, too. - url_loader_factory_.AddResponse(kSellerUrl.spec(), "", net::HTTP_NOT_FOUND); - Result res = RunStandardAuction(); - EXPECT_TRUE(res.ad_url.is_empty()); - EXPECT_TRUE(res.interest_group_owner.opaque()); - EXPECT_EQ("", res.interest_group_name); - EXPECT_FALSE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - - EXPECT_EQ(0, url_loader_factory_.NumPending()); - EXPECT_THAT(res.errors, - testing::ElementsAre( - "Failed to load https://adstuff.publisher1.com/auction.js " - "HTTP status = 404 Not Found.")); -} - -// An auction where bidders don't requested trusted bidding signals. -TEST_F(AuctionRunnerTest, NoTrustedBiddingSignals) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - false /* has_signals */, "k1", "a")); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - false /* has_signals */, "l2", "b")); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - - std::vector<mojom::BiddingInterestGroupPtr> bidders; - bidders.push_back(MakeInterestGroup(kBidder1, kBidder1Name, kBidder1Url, - absl::nullopt, {"k1", "k2"}, - GURL("https://ad1.com"))); - bidders.push_back(MakeInterestGroup(kBidder2, kBidder2Name, kBidder2Url, - absl::nullopt, {"l1", "l2"}, - GURL("https://ad2.com"))); - - Result res = RunAuctionAndWait( - kSellerUrl, std::move(bidders), - R"({"isAuctionSignals": true})", /* auction_signals_json */ - mojom::BrowserSignals::New( - url::Origin::Create(GURL("https://publisher1.com")), - url::Origin::Create(kSellerUrl))); - - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT(res.errors, testing::ElementsAre()); -} - -// An auction where trusted bidding signals are requested, but the fetch 404s. -TEST_F(AuctionRunnerTest, TrustedBiddingSignals404) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - false /* has_signals */, "k1", "a")); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - false /* has_signals */, "l2", "b")); - url_loader_factory_.AddResponse( - kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2", "", - net::HTTP_NOT_FOUND); - url_loader_factory_.AddResponse( - kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2", "", - net::HTTP_NOT_FOUND); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT(res.errors, - testing::ElementsAre("Failed to load " - "https://trustedsignaller.org/" - "signals?hostname=publisher1.com&keys=k1,k2 " - "HTTP status = 404 Not Found.", - "Failed to load " - "https://trustedsignaller.org/" - "signals?hostname=publisher1.com&keys=l1,l2 " - "HTTP status = 404 Not Found.")); -} - -// A successful auction where seller reporting worklet doesn't set a URL. -TEST_F(AuctionRunnerTest, NoReportResultUrl) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a")); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b")); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, - MakeAuctionScriptNoReportUrl()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_TRUE(res.bidder_report->report_requested); - EXPECT_EQ("https://buyer-reporting.example.com/", - res.bidder_report->report_url.spec()); - EXPECT_THAT(res.errors, testing::ElementsAre()); -} - -// A successful auction where bidder reporting worklet doesn't set a URL. -TEST_F(AuctionRunnerTest, NoReportWinUrl) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a") + - kReportWinNoUrl); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b") + - kReportWinNoUrl); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, MakeAuctionScript()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_EQ("https://reporting.example.com/", - res.seller_report->report_url.spec()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - EXPECT_THAT(res.errors, testing::ElementsAre()); -} - -// A successful auction where neither reporting worklets sets a URL. -TEST_F(AuctionRunnerTest, NeitherReportUrl) { - AddJavascriptResponse( - &url_loader_factory_, kBidder1Url, - MakeBidScript("1", "https://ad1.com/", kBidder1, kBidder1Name, - true /* has_signals */, "k1", "a") + - kReportWinNoUrl); - AddJavascriptResponse( - &url_loader_factory_, kBidder2Url, - MakeBidScript("2", "https://ad2.com/", kBidder2, kBidder2Name, - true /* has_signals */, "l2", "b") + - kReportWinNoUrl); - AddJavascriptResponse(&url_loader_factory_, kSellerUrl, - MakeAuctionScriptNoReportUrl()); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=k1,k2"), - R"({"k1":"a", "k2": "b", "extra": "c"})"); - AddJsonResponse( - &url_loader_factory_, - GURL(kTrustedSignalsUrl.spec() + "?hostname=publisher1.com&keys=l1,l2"), - R"({"l1":"a", "l2": "b", "extra": "c"})"); - - Result res = RunStandardAuction(); - EXPECT_EQ("https://ad2.com/", res.ad_url.spec()); - EXPECT_EQ("https://anotheradthing.com", res.interest_group_owner.Serialize()); - EXPECT_EQ("Another Ad Thing", res.interest_group_name); - EXPECT_TRUE(res.seller_report->success); - EXPECT_TRUE(res.seller_report->report_url.is_empty()); - EXPECT_FALSE(res.bidder_report->report_requested); - EXPECT_TRUE(res.bidder_report->report_url.is_empty()); - EXPECT_THAT(res.errors, testing::ElementsAre()); -} - -} // namespace -} // namespace auction_worklet
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.cc b/content/services/auction_worklet/auction_worklet_service_impl.cc index d2f66d7c..b3c3b14 100644 --- a/content/services/auction_worklet/auction_worklet_service_impl.cc +++ b/content/services/auction_worklet/auction_worklet_service_impl.cc
@@ -4,11 +4,14 @@ #include "content/services/auction_worklet/auction_worklet_service_impl.h" +#include <memory> #include <string> #include <utility> -#include "content/services/auction_worklet/auction_runner.h" +#include "content/services/auction_worklet/auction_v8_helper.h" +#include "content/services/auction_worklet/bidder_worklet.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/seller_worklet.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" @@ -21,15 +24,39 @@ AuctionWorkletServiceImpl::~AuctionWorkletServiceImpl() = default; -void AuctionWorkletServiceImpl::RunAuction( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback) { - AuctionRunner::CreateAndStart( - std::move(url_loader_factory), std::move(auction_config), - std::move(bidders), std::move(browser_signals), std::move(callback)); +void AuctionWorkletServiceImpl::LoadBidderWorkletAndGenerateBid( + mojo::PendingReceiver<mojom::BidderWorklet> bidder_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + mojom::BiddingInterestGroupPtr bidding_interest_group, + const absl::optional<std::string>& auction_signals_json, + const absl::optional<std::string>& per_buyer_signals_json, + const url::Origin& top_window_origin, + const url::Origin& seller_origin, + base::Time auction_start_time, + LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback) { + bidder_worklets_.Add( + std::make_unique<BidderWorklet>( + &auction_v8_helper_, std::move(pending_url_loader_factory), + std::move(bidding_interest_group), auction_signals_json, + per_buyer_signals_json, top_window_origin, seller_origin, + auction_start_time, + std::move(load_bidder_worklet_and_generate_bid_callback)), + std::move(bidder_worklet_receiver)); +} + +void AuctionWorkletServiceImpl::LoadSellerWorklet( + mojo::PendingReceiver<mojom::SellerWorklet> seller_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + const GURL& script_source_url, + LoadSellerWorkletCallback load_seller_worklet_callback) { + seller_worklets_.Add( + std::make_unique<SellerWorklet>( + &auction_v8_helper_, std::move(pending_url_loader_factory), + script_source_url, std::move(load_seller_worklet_callback)), + std::move(seller_worklet_receiver)); } } // namespace auction_worklet
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.h b/content/services/auction_worklet/auction_worklet_service_impl.h index 309ab31..94c22c46 100644 --- a/content/services/auction_worklet/auction_worklet_service_impl.h +++ b/content/services/auction_worklet/auction_worklet_service_impl.h
@@ -5,15 +5,20 @@ #ifndef CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_WORKLET_SERVICE_IMPL_H_ #define CONTENT_SERVICES_AUCTION_WORKLET_AUCTION_WORKLET_SERVICE_IMPL_H_ -#include <vector> - +#include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.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" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/unique_receiver_set.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" namespace auction_worklet { +class BidderWorklet; +class SellerWorklet; + // mojom::AuctionWorkletService implementation. This is intended to run in a // sandboxed utility process. class AuctionWorkletServiceImpl : public mojom::AuctionWorkletService { @@ -26,15 +31,34 @@ ~AuctionWorkletServiceImpl() override; // mojom::AuctionWorkletService implementation: - void RunAuction( - mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory, - blink::mojom::AuctionAdConfigPtr auction_config, - std::vector<mojom::BiddingInterestGroupPtr> bidders, - mojom::BrowserSignalsPtr browser_signals, - mojom::AuctionWorkletService::RunAuctionCallback callback) override; + void LoadBidderWorkletAndGenerateBid( + mojo::PendingReceiver<mojom::BidderWorklet> bidder_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + mojom::BiddingInterestGroupPtr bidding_interest_group, + const absl::optional<std::string>& auction_signals_json, + const absl::optional<std::string>& per_buyer_signals_json, + const url::Origin& top_window_origin, + const url::Origin& seller_origin, + base::Time auction_start_time, + LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback) override; + void LoadSellerWorklet( + mojo::PendingReceiver<mojom::SellerWorklet> seller_worklet_receiver, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, + const GURL& script_source_url, + LoadSellerWorkletCallback load_seller_worklet_callback) override; private: mojo::Receiver<mojom::AuctionWorkletService> receiver_; + + // `auction_v8_helper_` needs to be before the worklets, since they refer to + // it, so need to be torn down before it is. + AuctionV8Helper auction_v8_helper_; + + mojo::UniqueReceiverSet<mojom::BidderWorklet> bidder_worklets_; + mojo::UniqueReceiverSet<mojom::SellerWorklet> seller_worklets_; }; } // namespace auction_worklet
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc index ced7edd9..67a07e1 100644 --- a/content/services/auction_worklet/bidder_worklet.cc +++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -23,6 +23,8 @@ #include "content/services/auction_worklet/worklet_loader.h" #include "gin/converter.h" #include "gin/dictionary.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/struct_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" @@ -48,65 +50,44 @@ return true; } -// Temporary utility to run callback asynchronously, to imitate behavior once -// this class starts implementing a Mojo API. -// -// TODO(mmenke): Remove once this class switches over to using Mojo. -void InvokeReportWinCallbackAsync(BidderWorklet::ReportWinCallback callback, - const absl::optional<GURL>& report_url, - const std::vector<std::string>& errors) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), report_url, errors)); -} - } // namespace -BidderWorklet::Bid::Bid(std::string ad, - double bid, - GURL render_url, - base::TimeDelta bid_duration) - : ad(std::move(ad)), - bid(bid), - render_url(std::move(render_url)), - bid_duration(bid_duration) { - DCHECK_GT(this->bid, 0); - DCHECK(this->render_url.is_valid()); -} - -BidderWorklet::Bid::Bid(const Bid& other) = default; -BidderWorklet::Bid::Bid(Bid&& other) = default; -BidderWorklet::Bid::~Bid() = default; -BidderWorklet::Bid& BidderWorklet::Bid::operator=(const Bid&) = default; -BidderWorklet::Bid& BidderWorklet::Bid::operator=(Bid&&) = default; - BidderWorklet::BidderWorklet( AuctionV8Helper* v8_helper, - network::mojom::URLLoaderFactory* url_loader_factory, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, mojom::BiddingInterestGroupPtr bidding_interest_group, const absl::optional<std::string>& auction_signals_json, const absl::optional<std::string>& per_buyer_signals_json, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_seller_origin, base::Time auction_start_time, - LoadScriptAndGenerateBidCallback load_script_and_generate_bid_callback) + mojom::AuctionWorkletService::LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback) : v8_helper_(v8_helper), script_source_url_( bidding_interest_group->group->bidding_url.value_or(GURL())), + load_bidder_worklet_and_generate_bid_callback_( + std::move(load_bidder_worklet_and_generate_bid_callback)), bidding_interest_group_(std::move(bidding_interest_group)), - load_script_and_generate_bid_callback_( - std::move(load_script_and_generate_bid_callback)), auction_signals_json_(auction_signals_json), per_buyer_signals_json_(per_buyer_signals_json), browser_signal_top_window_hostname_( browser_signal_top_window_origin.host()), browser_signal_seller_(browser_signal_seller_origin.Serialize()), auction_start_time_(auction_start_time) { - DCHECK(load_script_and_generate_bid_callback_); + DCHECK(load_bidder_worklet_and_generate_bid_callback_); + + // Bind URLLoaderFactory. Remote is not needed after this method completes, + // since requests will continue after the URLLoaderFactory pipe has been + // closed, so no need to keep it around after requests have been issued. + mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory( + std::move(pending_url_loader_factory)); // TODO(mmenke): Remove up the value_or() for script_source_url_- auction // worklets shouldn't be created when there's no bidding URL. worklet_loader_ = std::make_unique<WorkletLoader>( - url_loader_factory, script_source_url_, v8_helper, + url_loader_factory.get(), script_source_url_, v8_helper_, base::BindOnce(&BidderWorklet::OnScriptDownloaded, base::Unretained(this))); @@ -116,16 +97,20 @@ !bidding_interest_group_->group->trusted_bidding_signals_keys->empty()) { trusted_bidding_signals_loading_ = true; trusted_bidding_signals_ = std::make_unique<TrustedBiddingSignals>( - url_loader_factory, + url_loader_factory.get(), *bidding_interest_group_->group->trusted_bidding_signals_keys, browser_signal_top_window_origin.host(), - *bidding_interest_group_->group->trusted_bidding_signals_url, v8_helper, + *bidding_interest_group_->group->trusted_bidding_signals_url, + v8_helper_, base::BindOnce(&BidderWorklet::OnTrustedBiddingSignalsDownloaded, base::Unretained(this))); } } -BidderWorklet::~BidderWorklet() = default; +BidderWorklet::~BidderWorklet() { + if (load_bidder_worklet_and_generate_bid_callback_) + InvokeBidCallbackOnError(); +} void BidderWorklet::ReportWin( const std::string& seller_signals_json, @@ -133,8 +118,6 @@ const std::string& browser_signal_ad_render_fingerprint, double browser_signal_bid, ReportWinCallback callback) { - callback = base::BindOnce(&InvokeReportWinCallbackAsync, std::move(callback)); - AuctionV8Helper::FullIsolateScope isolate_scope(v8_helper_); v8::Isolate* isolate = v8_helper_->isolate(); @@ -201,7 +184,7 @@ void BidderWorklet::OnScriptDownloaded( std::unique_ptr<v8::Global<v8::UnboundScript>> worklet_script, absl::optional<std::string> error_msg) { - DCHECK(load_script_and_generate_bid_callback_); + DCHECK(load_bidder_worklet_and_generate_bid_callback_); if (worklet_script == nullptr) { // Abort loading trusted bidding signals, if it hasn't completed already. @@ -219,7 +202,7 @@ bool load_result, absl::optional<std::string> error_msg) { // Worklet results should still be pending. - DCHECK(load_script_and_generate_bid_callback_); + DCHECK(load_bidder_worklet_and_generate_bid_callback_); DCHECK(trusted_bidding_signals_loading_); trusted_bidding_signals_error_msg_ = std::move(error_msg); @@ -231,7 +214,7 @@ } void BidderWorklet::GenerateBidIfReady() { - DCHECK(load_script_and_generate_bid_callback_); + DCHECK(load_bidder_worklet_and_generate_bid_callback_); if (trusted_bidding_signals_loading_ || !worklet_script_) return; @@ -399,8 +382,9 @@ errors.emplace_back( std::move(trusted_bidding_signals_error_msg_).value()); } - std::move(load_script_and_generate_bid_callback_) - .Run(Bid(std::move(ad_json), bid, std::move(render_url), + std::move(load_bidder_worklet_and_generate_bid_callback_) + .Run(mojom::BidderWorkletBid::New( + std::move(ad_json), bid, std::move(render_url), base::TimeTicks::Now() - start /* bid_duration */), errors); return; @@ -417,11 +401,10 @@ std::vector<std::string> errors; if (error_msg) errors.emplace_back(std::move(error_msg).value()); - if (trusted_bidding_signals_error_msg_) { + if (trusted_bidding_signals_error_msg_) errors.emplace_back(std::move(trusted_bidding_signals_error_msg_).value()); - } - std::move(load_script_and_generate_bid_callback_) - .Run(absl::nullopt /* bid */, errors); + std::move(load_bidder_worklet_and_generate_bid_callback_) + .Run(mojom::BidderWorkletBidPtr(), errors); } } // namespace auction_worklet
diff --git a/content/services/auction_worklet/bidder_worklet.h b/content/services/auction_worklet/bidder_worklet.h index fd88752..b455c7d 100644 --- a/content/services/auction_worklet/bidder_worklet.h +++ b/content/services/auction_worklet/bidder_worklet.h
@@ -12,8 +12,9 @@ #include "base/callback.h" #include "base/time/time.h" -#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/struct_ptr.h" #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -39,57 +40,8 @@ // to both be used for two generateBid() calls for different interest groups // with the same owner in the same auction, and to be used to bid for the same // interest group in different auctions. -class BidderWorklet { +class BidderWorklet : public mojom::BidderWorklet { public: - // Structure containing information about a bid returned by invoking a - // worklet's generageBid() method. If no bid is made, no Bid is constructed. - struct Bid { - Bid(std::string ad, - double bid, - GURL render_url, - base::TimeDelta bid_duration); - - Bid(const Bid& other); - Bid(Bid&& other); - - ~Bid(); - - Bid& operator=(const Bid&); - Bid& operator=(Bid&&); - - // JSON string to be passed to the scoring function. - std::string ad; - - // Offered bid value. - double bid; - - // Render URL, if any bid was made. - GURL render_url; - - // How long it took to run the script that generated the bid. - base::TimeDelta bid_duration; - }; - - // If no bid is generated, `bid` is null. - // - // `errors` contains error messages for debugging. This isn't guaranteed - // to be produced for all failures, so should not be checked to identify - // bidding failures errors. It's also possible for there to be an error - // message on success, in the case the trusted bidding signals failed to load - // - auctions will still be run without it, but `errors` will be populated - // with information about the load failure. - using LoadScriptAndGenerateBidCallback = - base::OnceCallback<void(absl::optional<Bid> bid, - const std::vector<std::string>& errors)>; - - // `report_url` is the URL to request to report displaying the ad. It is - // nullopt on error or if report is requested. `errors` is a list of - // errors that occurred, if any. `errors` may be non-empty on success, or - // empty on failure. - using ReportWinCallback = - base::OnceCallback<void(const absl::optional<GURL>& report_url, - const std::vector<std::string>& errors)>; - // Starts loading the worklet script on construction, as well as the trusted // bidding data, if necessary. Will then call the script's generateBid() // function and invoke the callback with the results. Callback will always be @@ -99,25 +51,27 @@ // Data is cached and will be reused ReportWin(). BidderWorklet( AuctionV8Helper* v8_helper, - network::mojom::URLLoaderFactory* url_loader_factory, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, mojom::BiddingInterestGroupPtr bidding_interest_group, const absl::optional<std::string>& auction_signals_json, const absl::optional<std::string>& per_buyer_signals_json, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_seller_origin, base::Time auction_start_time, - LoadScriptAndGenerateBidCallback load_script_and_generate_bid_callback); + mojom::AuctionWorkletService::LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback); explicit BidderWorklet(const BidderWorklet&) = delete; BidderWorklet& operator=(const BidderWorklet&) = delete; - ~BidderWorklet(); - // Calls reportWin(), and asynchronously invokes `callback` with reporting - // information. May only be called once the worklet has successfully loaded. + ~BidderWorklet() override; + + // mojom::BidderWorklet implementation: void ReportWin(const std::string& seller_signals_json, const GURL& browser_signal_render_url, const std::string& browser_signal_ad_render_fingerprint, double browser_signal_bid, - ReportWinCallback callback); + ReportWinCallback callback) override; private: void OnScriptDownloaded( @@ -141,11 +95,11 @@ AuctionV8Helper* const v8_helper_; - const GURL script_source_url_; + GURL script_source_url_; + mojom::AuctionWorkletService::LoadBidderWorkletAndGenerateBidCallback + load_bidder_worklet_and_generate_bid_callback_; + const mojom::BiddingInterestGroupPtr bidding_interest_group_; - - LoadScriptAndGenerateBidCallback load_script_and_generate_bid_callback_; - const absl::optional<std::string> auction_signals_json_; const absl::optional<std::string> per_buyer_signals_json_; const std::string browser_signal_top_window_hostname_;
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc index e86467f..c4fe050 100644 --- a/content/services/auction_worklet/bidder_worklet_unittest.cc +++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -17,6 +17,7 @@ #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/trusted_bidding_signals.h" #include "content/services/auction_worklet/worklet_test_util.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/struct_ptr.h" #include "net/http/http_status_code.h" #include "services/network/test/test_url_loader_factory.h" @@ -110,10 +111,10 @@ // specified return line Then runs the script, expecting the provided result. void RunGenerateBidWithReturnValueExpectingResult( const std::string& raw_return_value, - const absl::optional<BidderWorklet::Bid> expected_bid, + mojom::BidderWorkletBidPtr expected_bid, std::vector<std::string> expected_errors = std::vector<std::string>()) { RunGenerateBidWithJavascriptExpectingResult( - CreateGenerateBidScript(raw_return_value), expected_bid, + CreateGenerateBidScript(raw_return_value), std::move(expected_bid), expected_errors); } @@ -121,22 +122,22 @@ // Javascript Then runs the script, expecting the provided result. void RunGenerateBidWithJavascriptExpectingResult( const std::string& javascript, - const absl::optional<BidderWorklet::Bid> expected_bid, + mojom::BidderWorkletBidPtr expected_bid, std::vector<std::string> expected_errors = std::vector<std::string>()) { SCOPED_TRACE(javascript); AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_, javascript); - RunGenerateBidExpectingResult(expected_bid, expected_errors); + RunGenerateBidExpectingResult(std::move(expected_bid), expected_errors); } // Loads and runs a generateBid() script, expecting the provided result. void RunGenerateBidExpectingResult( - const absl::optional<BidderWorklet::Bid> expected_bid, + mojom::BidderWorkletBidPtr expected_bid, std::vector<std::string> expected_errors = std::vector<std::string>()) { auto bidder_worklet = CreateWorkletAndGenerateBid(); - EXPECT_EQ(expected_bid.has_value(), bid_.has_value()); - if (expected_bid.has_value() && bid_.has_value()) { + EXPECT_EQ(expected_bid.is_null(), bid_.is_null()); + if (expected_bid && bid_) { EXPECT_EQ(expected_bid->ad, bid_->ad); EXPECT_EQ(expected_bid->bid, bid_->bid); EXPECT_EQ(expected_bid->render_url, bid_->render_url); @@ -193,11 +194,8 @@ run_loop.Run(); } - // Create a BidderWorklet, waiting for the URLLoader to complete. Returns - // nullptr on failure. - std::unique_ptr<BidderWorklet> CreateWorkletAndGenerateBid() { - CHECK(!load_script_run_loop_); - + // Creates a BiddingInterestGroup based on test fixture configuration. + mojom::BiddingInterestGroupPtr CreateBiddingInterestGroup() { blink::mojom::InterestGroupPtr interest_group = blink::mojom::InterestGroup::New(); interest_group->owner = interest_group_owner_; @@ -224,30 +222,52 @@ mojom::BiddingInterestGroupPtr bidding_interest_group = mojom::BiddingInterestGroup::New(std::move(interest_group), std::move(bidding_browser_signals)); + return bidding_interest_group; + } - auto bidder_worket = std::make_unique<BidderWorklet>( - &v8_helper_, &url_loader_factory_, std::move(bidding_interest_group), - null_auction_signals_ - ? absl::nullopt - : absl::make_optional<std::string>(auction_signals_), - null_per_buyer_signals_ - ? absl::nullopt - : absl::make_optional<std::string>(per_buyer_signals_), - browser_signal_top_window_origin_, browser_signal_seller_origin_, - auction_start_time_, - base::BindOnce(&BidderWorkletTest::CreateWorkletCallback, - base::Unretained(this))); + // Create a BidderWorklet, waiting for the URLLoader to complete. Returns + // a null Remote on failure. + mojo::Remote<mojom::BidderWorklet> CreateWorkletAndGenerateBid() { + CHECK(!load_script_run_loop_); + + mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; + url_loader_factory_.Clone( + url_loader_factory.InitWithNewPipeAndPassReceiver()); + + mojo::Remote<mojom::BidderWorklet> bidder_worklet; + mojo::MakeSelfOwnedReceiver( + std::make_unique<BidderWorklet>( + &v8_helper_, std::move(url_loader_factory), + CreateBiddingInterestGroup(), + null_auction_signals_ + ? absl::nullopt + : absl::make_optional<std::string>(auction_signals_), + null_per_buyer_signals_ + ? absl::nullopt + : absl::make_optional<std::string>(per_buyer_signals_), + browser_signal_top_window_origin_, browser_signal_seller_origin_, + auction_start_time_, + base::BindOnce(&BidderWorkletTest::CreateWorkletCallback, + base::Unretained(this))), + bidder_worklet.BindNewPipeAndPassReceiver()); load_script_run_loop_ = std::make_unique<base::RunLoop>(); load_script_run_loop_->Run(); load_script_run_loop_.reset(); if (!bid_) - return nullptr; - return bidder_worket; + return mojo::Remote<mojom::BidderWorklet>(); + return bidder_worklet; } - const absl::optional<BidderWorklet::Bid>& bid() const { return bid_; } + const mojom::BidderWorkletBidPtr& bid() const { return bid_; } const std::vector<std::string> bid_errors() const { return bid_errors_; } + void CreateWorkletCallback(mojom::BidderWorkletBidPtr bid, + const std::vector<std::string>& errors) { + bid_ = std::move(bid); + bid_errors_ = std::move(errors); + load_script_run_loop_->Quit(); + } + protected: std::vector<mojo::StructPtr<mojom::PreviousWin>> CloneWinList( const std::vector<mojo::StructPtr<mojom::PreviousWin>>& prev_win_list) { @@ -258,13 +278,6 @@ return out; } - void CreateWorkletCallback(absl::optional<BidderWorklet::Bid> bid, - const std::vector<std::string>& errors) { - bid_ = std::move(bid); - bid_errors_ = errors; - load_script_run_loop_->Quit(); - } - base::test::TaskEnvironment task_environment_; // Values used to construct the BiddingInterestGroup passed to the @@ -308,19 +321,49 @@ std::unique_ptr<base::RunLoop> load_script_run_loop_; // Values passed to the GenerateBidCallback(). - absl::optional<BidderWorklet::Bid> bid_; + mojom::BidderWorkletBidPtr bid_; std::vector<std::string> bid_errors_; network::TestURLLoaderFactory url_loader_factory_; AuctionV8Helper v8_helper_; }; +// Test the case the BidderWorklet pipe is closed before invoking the +// LoadBidderWorkletAndGenerateBidCallback. +// LoadBidderWorkletAndGenerateBidCallback should be invoked, and there should +// be no Mojo exception due to destroying the creation callback without invoking +// it. +TEST_F(BidderWorkletTest, PipeClosed) { + mojo::Remote<mojom::BidderWorklet> bidder_worklet; + mojo::PendingReceiver<network::mojom::URLLoaderFactory> + url_loader_factory_receiver; + + mojo::MakeSelfOwnedReceiver( + std::make_unique<BidderWorklet>( + &v8_helper_, + url_loader_factory_receiver.InitWithNewPipeAndPassRemote(), + CreateBiddingInterestGroup(), + absl::nullopt /* auction_signals_json */, + absl::nullopt /* per_buyer_signals_json */, + browser_signal_top_window_origin_, browser_signal_seller_origin_, + auction_start_time_, + base::BindOnce(&BidderWorkletTest::CreateWorkletCallback, + base::Unretained(this))), + bidder_worklet.BindNewPipeAndPassReceiver()); + load_script_run_loop_ = std::make_unique<base::RunLoop>(); + bidder_worklet.reset(); + + load_script_run_loop_->Run(); + load_script_run_loop_.reset(); + EXPECT_FALSE(bid_); +} + TEST_F(BidderWorkletTest, NetworkError) { url_loader_factory_.AddResponse(interest_group_bidding_url_.spec(), CreateBasicGenerateBidScript(), net::HTTP_NOT_FOUND); RunGenerateBidExpectingResult( - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"Failed to load https://url.test/ HTTP status = 404 Not Found."}); } @@ -341,8 +384,8 @@ // CreateBasicGenerateBidScript() does indeed work. RunGenerateBidWithJavascriptExpectingResult( CreateBasicGenerateBidScript(), - BidderWorklet::Bid("[\"ad\"]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "[\"ad\"]", 1, GURL("https://response.test/"), base::TimeDelta())); // -------- // Vary ad @@ -351,43 +394,44 @@ // Make sure "ad" can be of a variety of JS object types. RunGenerateBidWithReturnValueExpectingResult( R"({ad: "ad", bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("\"ad\"", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("\"ad\"", 1, GURL("https://response.test/"), + base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: {a:1,b:null}, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"({"a":1,"b":null})", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"({"a":1,"b":null})", 1, + GURL("https://response.test/"), + base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: [2.5,[]], bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("[2.5,[]]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "[2.5,[]]", 1, GURL("https://response.test/"), base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: -5, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("-5", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("-5", 1, GURL("https://response.test/"), + base::TimeDelta())); // Some values that can't be represented in JSON become null. RunGenerateBidWithReturnValueExpectingResult( R"({ad: 0/0, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: [globalThis.not_defined], bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("[null]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("[null]", 1, GURL("https://response.test/"), + base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: [function() {return 1;}], bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("[null]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("[null]", 1, GURL("https://response.test/"), + base::TimeDelta())); // Other values JSON can't represent result in failing instead of null. RunGenerateBidWithReturnValueExpectingResult( R"({ad: globalThis.not_defined, bid:1, render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: function() {return 1;}, bid:1, render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); @@ -400,7 +444,7 @@ return {ad: a, bid:1, render:"https://response.test/"}; } )", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); @@ -411,48 +455,48 @@ // Valid positive bid values. RunGenerateBidWithReturnValueExpectingResult( R"({ad: "ad", bid:1.5, render:"https://response.test/"})", - BidderWorklet::Bid("\"ad\"", 1.5, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "\"ad\"", 1.5, GURL("https://response.test/"), base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: "ad", bid:2, render:"https://response.test/"})", - BidderWorklet::Bid("\"ad\"", 2, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("\"ad\"", 2, GURL("https://response.test/"), + base::TimeDelta())); RunGenerateBidWithReturnValueExpectingResult( R"({ad: "ad", bid:0.001, render:"https://response.test/"})", - BidderWorklet::Bid("\"ad\"", 0.001, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "\"ad\"", 0.001, GURL("https://response.test/"), base::TimeDelta())); // Bids <= 0. RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:0, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:-10, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:-1.5, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); // Infinite and NaN bid. RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1/0, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:-1/0, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:0/0, render:"https://response.test/"})", - absl::nullopt /* expected_bid */); + mojom::BidderWorkletBidPtr() /* expected_bid */); // Non-numeric bid. RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:"1", render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:[1], render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); @@ -462,48 +506,50 @@ RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("[\"ad\"]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "[\"ad\"]", 1, GURL("https://response.test/"), base::TimeDelta())); // Disallowed schemes. RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"http://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"chrome-extension://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"about:blank"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"data:,foo"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); // Invalid URLs. RunGenerateBidWithReturnValueExpectingResult( - R"({ad: ["ad"], bid:1, render:"test"})", absl::nullopt /* expected_bid */, + R"({ad: ["ad"], bid:1, render:"test"})", + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:"http://"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned " "render_url isn't a valid https:// URL."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], bid:1, render:["http://response.test/"]})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); RunGenerateBidWithReturnValueExpectingResult( - R"({ad: ["ad"], bid:1, render:9})", absl::nullopt /* expected_bid */, + R"({ad: ["ad"], bid:1, render:9})", + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); @@ -513,22 +559,23 @@ // No return value. RunGenerateBidWithReturnValueExpectingResult( - "", absl::nullopt /* expected_bid */, + "", mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value not an object."}); // Missing value. RunGenerateBidWithReturnValueExpectingResult( R"({bid:"a", render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: ["ad"], render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); RunGenerateBidWithReturnValueExpectingResult( - R"({ad: ["ad"], bid:"a"})", absl::nullopt /* expected_bid */, + R"({ad: ["ad"], bid:"a"})", + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() return value " "has incorrect structure."}); @@ -539,18 +586,18 @@ return {ad: ["ad"], bid:1, render:"https://response.test/"}; } )", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ `generateBid` is not a function."}); RunGenerateBidWithJavascriptExpectingResult( - "", absl::nullopt /* expected_bid */, + "", mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ `generateBid` is not a function."}); RunGenerateBidWithJavascriptExpectingResult( - "5", absl::nullopt /* expected_bid */, + "5", mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ `generateBid` is not a function."}); // Throw exception. RunGenerateBidWithJavascriptExpectingResult( - "shrimp", absl::nullopt /* expected_bid */, + "shrimp", mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/:1 Uncaught ReferenceError: " "shrimp is not defined."}); } @@ -559,7 +606,7 @@ TEST_F(BidderWorkletTest, GenerateBidDateNotAvailable) { RunGenerateBidWithReturnValueExpectingResult( R"({ad: Date().toString(), bid:1, render:"https://response.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/:4 Uncaught ReferenceError: Date is not defined."}); } @@ -605,10 +652,10 @@ base::StringPrintf( R"({ad: %s, bid:1, render:"https://response.test/"})", test_case.name), - test_case.is_json - ? absl::optional<BidderWorklet::Bid>() - : BidderWorklet::Bid(R"("foo")", 1, GURL("https://response.test/"), - base::TimeDelta())); + test_case.is_json ? mojom::BidderWorkletBidPtr() + : mojom::BidderWorkletBid::New( + R"("foo")", 1, GURL("https://response.test/"), + base::TimeDelta())); *test_case.value_ptr = R"("foo")"; RunGenerateBidWithReturnValueExpectingResult( @@ -616,11 +663,12 @@ R"({ad: %s, bid:1, render:"https://response.test/"})", test_case.name), test_case.is_json - ? BidderWorklet::Bid(R"("foo")", 1, GURL("https://response.test/"), - base::TimeDelta()) - : BidderWorklet::Bid(R"("\"foo\"")", 1, - GURL("https://response.test/"), - base::TimeDelta())); + ? mojom::BidderWorkletBid::New(R"("foo")", 1, + GURL("https://response.test/"), + base::TimeDelta()) + : mojom::BidderWorkletBid::New(R"("\"foo\"")", 1, + GURL("https://response.test/"), + base::TimeDelta())); *test_case.value_ptr = "[1]"; RunGenerateBidWithReturnValueExpectingResult( @@ -628,38 +676,44 @@ R"({ad: %s[0], bid:1, render:"https://response.test/"})", test_case.name), test_case.is_json - ? BidderWorklet::Bid("1", 1, GURL("https://response.test/"), - base::TimeDelta()) - : BidderWorklet::Bid(R"("[")", 1, GURL("https://response.test/"), - base::TimeDelta())); + ? mojom::BidderWorkletBid::New( + "1", 1, GURL("https://response.test/"), base::TimeDelta()) + : mojom::BidderWorkletBid::New(R"("[")", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); } interest_group_owner_ = url::Origin::Create(GURL("https://foo.test/")); RunGenerateBidWithReturnValueExpectingResult( R"({ad: interestGroup.owner, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("https://foo.test")", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("https://foo.test")", 1, + GURL("https://response.test/"), + base::TimeDelta())); interest_group_owner_ = url::Origin::Create(GURL("https://[::1]:40000/")); RunGenerateBidWithReturnValueExpectingResult( R"({ad: interestGroup.owner, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("https://[::1]:40000")", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("https://[::1]:40000")", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); browser_signal_seller_origin_ = url::Origin::Create(GURL("https://foo.test/")); RunGenerateBidWithReturnValueExpectingResult( R"({ad: browserSignals.seller, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("https://foo.test")", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("https://foo.test")", 1, + GURL("https://response.test/"), + base::TimeDelta())); + browser_signal_seller_origin_ = url::Origin::Create(GURL("https://[::1]:40000/")); RunGenerateBidWithReturnValueExpectingResult( R"({ad: browserSignals.seller, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("https://[::1]:40000")", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("https://[::1]:40000")", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); // Test the empty `userBiddingSignals` case, too. It's actually an optional @@ -669,16 +723,18 @@ interest_group_user_bidding_signals_ = ""; RunGenerateBidWithReturnValueExpectingResult( R"({ad:typeof interestGroup.userBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("undefined")", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("undefined")", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); browser_signal_top_window_origin_ = url::Origin::Create(GURL("https://top.window.test/")); RunGenerateBidWithReturnValueExpectingResult( R"({ad: browserSignals.topWindowHostname, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"("top.window.test")", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"("top.window.test")", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); const struct IntegerTestCase { @@ -698,16 +754,16 @@ base::StringPrintf( R"({ad: %s, bid:1, render:"https://response.test/"})", test_case.name), - BidderWorklet::Bid("0", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("0", 1, GURL("https://response.test/"), + base::TimeDelta())); *test_case.value_ptr = 10; RunGenerateBidWithReturnValueExpectingResult( base::StringPrintf( R"({ad: %s, bid:1, render:"https://response.test/"})", test_case.name), - BidderWorklet::Bid("10", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("10", 1, GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); } @@ -716,7 +772,7 @@ // A bid URL that's not in the InterestGroup's ads list should fail. RunGenerateBidWithReturnValueExpectingResult( R"({ad: 0, bid:1, render:"https://response2.test/"})", - absl::nullopt /* expected_bid */, + mojom::BidderWorkletBidPtr() /* expected_bid */, {"https://url.test/ generateBid() returned render_url isn't one of " "the registered creative URLs."}); @@ -726,17 +782,18 @@ GURL("https://response2.test/"), R"(["metadata"])" /* metadata */)); RunGenerateBidWithReturnValueExpectingResult( R"({ad: interestGroup.ads, bid:1, render:"https://response2.test/"})", - BidderWorklet::Bid("[{\"renderUrl\":\"https://response.test/\"}," - "{\"renderUrl\":\"https://response2.test/" - "\",\"metadata\":[\"metadata\"]}]", - 1, GURL("https://response2.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "[{\"renderUrl\":\"https://response.test/\"}," + "{\"renderUrl\":\"https://response2.test/" + "\",\"metadata\":[\"metadata\"]}]", + 1, GURL("https://response2.test/"), base::TimeDelta())); // Make sure `metadata` is treated as an object, instead of a raw string. RunGenerateBidWithReturnValueExpectingResult( R"({ad: interestGroup.ads[1].metadata[0], bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("\"metadata\"", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("\"metadata\"", 1, + GURL("https://response.test/"), + base::TimeDelta())); } // Test handling of null auctionSignals and perBuyerSignals to generateBid. @@ -751,33 +808,33 @@ null_auction_signals_ = false; null_per_buyer_signals_ = false; RunGenerateBidWithReturnValueExpectingResult( - kRetVal, - BidderWorklet::Bid("[false,false]", 1, GURL("https://response.test/"), - base::TimeDelta())); + kRetVal, mojom::BidderWorkletBid::New("[false,false]", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); null_auction_signals_ = false; null_per_buyer_signals_ = true; RunGenerateBidWithReturnValueExpectingResult( - kRetVal, - BidderWorklet::Bid("[false,true]", 1, GURL("https://response.test/"), - base::TimeDelta())); + kRetVal, mojom::BidderWorkletBid::New("[false,true]", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); null_auction_signals_ = true; null_per_buyer_signals_ = false; RunGenerateBidWithReturnValueExpectingResult( - kRetVal, - BidderWorklet::Bid("[true,false]", 1, GURL("https://response.test/"), - base::TimeDelta())); + kRetVal, mojom::BidderWorkletBid::New("[true,false]", 1, + GURL("https://response.test/"), + base::TimeDelta())); SetDefaultParameters(); null_auction_signals_ = true; null_per_buyer_signals_ = true; RunGenerateBidWithReturnValueExpectingResult( kRetVal, - BidderWorklet::Bid("[true,true]", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New( + "[true,true]", 1, GURL("https://response.test/"), base::TimeDelta())); } // Utility methods to create vectors of PreviousWin. Needed because StructPtr's @@ -867,8 +924,9 @@ base::StringPrintf( R"({ad: %s, bid:1, render:"https://response.test/"})", test_case.ad), - BidderWorklet::Bid(test_case.expected_ad, 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(test_case.expected_ad, 1, + GURL("https://response.test/"), + base::TimeDelta())); } } @@ -888,8 +946,8 @@ // made. RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta())); // Request with TrustedBiddingSignals keys and null URL. No request should be // made. @@ -897,8 +955,8 @@ std::vector<std::string>({"key1", "key2"}); RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta())); // Request with TrustedBiddingSignals URL and null keys. No request should be // made. @@ -906,16 +964,16 @@ interest_group_trusted_bidding_signals_keys_.reset(); RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta())); // Request with TrustedBiddingSignals URL and empty keys. No request should be // made. interest_group_trusted_bidding_signals_keys_ = std::vector<std::string>(); RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta())); + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta())); // Request with valid TrustedBiddingSignals URL and non-empty keys. Request // should be made. The request fails. @@ -925,8 +983,8 @@ net::HTTP_NOT_FOUND); RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid("null", 1, GURL("https://response.test/"), - base::TimeDelta()), + mojom::BidderWorkletBid::New("null", 1, GURL("https://response.test/"), + base::TimeDelta()), {"Failed to load " "https://signals.test/?hostname=top.window.test&keys=key1,key2 HTTP " "status = 404 Not Found."}); @@ -936,8 +994,9 @@ AddJsonResponse(&url_loader_factory_, kFullSignalsUrl, kJson); RunGenerateBidWithReturnValueExpectingResult( R"({ad: trustedBiddingSignals, bid:1, render:"https://response.test/"})", - BidderWorklet::Bid(R"({"key1":1,"key2":[2]})", 1, - GURL("https://response.test/"), base::TimeDelta())); + mojom::BidderWorkletBid::New(R"({"key1":1,"key2":[2]})", 1, + GURL("https://response.test/"), + base::TimeDelta())); } TEST_F(BidderWorkletTest, ReportWin) { @@ -1065,7 +1124,8 @@ // JSON values passed the generateBid() result in failures there, before // reportWin is called. RunGenerateBidWithJavascriptExpectingResult( - CreateBasicGenerateBidScript(), absl::nullopt /* expected_bid */); + CreateBasicGenerateBidScript(), + mojom::BidderWorkletBidPtr() /* expected_bid */); } *test_case.value_ptr = R"(["https://foo.test/"])";
diff --git a/content/services/auction_worklet/public/mojom/BUILD.gn b/content/services/auction_worklet/public/mojom/BUILD.gn index 3b427b85..7627b86 100644 --- a/content/services/auction_worklet/public/mojom/BUILD.gn +++ b/content/services/auction_worklet/public/mojom/BUILD.gn
@@ -6,7 +6,11 @@ mojom("mojom") { generate_java = false - sources = [ "auction_worklet_service.mojom" ] + sources = [ + "auction_worklet_service.mojom", + "bidder_worklet.mojom", + "seller_worklet.mojom", + ] deps = [ "//mojo/public/mojom/base", "//services/network/public/mojom",
diff --git a/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom b/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom index 2b0adb60..c3440ced 100644 --- a/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom +++ b/content/services/auction_worklet/public/mojom/auction_worklet_service.mojom
@@ -4,124 +4,114 @@ module auction_worklet.mojom; +import "content/services/auction_worklet/public/mojom/bidder_worklet.mojom"; +import "content/services/auction_worklet/public/mojom/seller_worklet.mojom"; import "mojo/public/mojom/base/time.mojom"; import "services/network/public/mojom/url_loader_factory.mojom"; import "third_party/blink/public/mojom/interest_group/interest_group_types.mojom"; import "url/mojom/origin.mojom"; import "url/mojom/url.mojom"; -struct PreviousWin { - // Approximate time a particular group won an auction. - mojo_base.mojom.Time time; - - // The ad object returned by that group's bidding function with the winning - // bid. - string ad_json; -}; - -// Information here corresponds to the interest group it's packaged with inside -// BiddingInterestGroup. -struct BiddingBrowserSignals { - // How many times this interest group has been joined in the period history - // is maintained. - int32 join_count; - - // How many times this interest group has made bids in auctions. - int32 bid_count; - - // Previous times the group won auctions. - array<PreviousWin> prev_wins; -}; - -struct BiddingInterestGroup { - blink.mojom.InterestGroup group; // User JS specified, stored by browser. - BiddingBrowserSignals signals; // Collected by browser. -}; - struct BrowserSignals { url.mojom.Origin top_frame_origin; url.mojom.Origin seller; }; -struct WinningBidderReport { - // true if the winning bidder worklet's reporting function ran successfully - // and set a reporting URL. - bool report_requested; - - // This is checked to be a https:// URL for `report_requested` to be true, but - // no restrictions on the destination are performed by AuctionRunner. - url.mojom.Url report_url; -}; - -struct SellerReport { - // true if the seller worklet's reporting function ran successfully. Unlike - // WinningBidderReport, this doesn't require the URL to be set and valid. - bool success; - string signals_for_winner_json; - - // If this is non-empty, it's a valid https:// URL, but no restrictions on - // destination beyond the scheme are enforced by AuctionRunner. - url.mojom.Url report_url; -}; - -// Used to load and run FLEDGE worklets. +// Used by the browser to load and run FLEDGE worklets in a sandboxed utility +// process. // See https://github.com/WICG/turtledove/blob/main/FLEDGE.md -// -// This is used from the browser, by AuctionManager, and runs in a dedicated -// utility process. The implementation is global (and stateless besides what's -// needed to handle an individual request). interface AuctionWorkletService { - // Runs an entire FLEDGE auction. + // Loads a FLEDGE bidder worklet, its same-origin realtime bidding signals + // URL (if necessary), and invokes its generateBid() method, returning + // the generate bid and associated data. // // Arguments: - // `url_loader_factory` is used to load worklet scripts and trusted bidding - // signals. It's recommended that the implementation be restricted to exactly - // those URLs (keeping in mind query parameter usage for trusted bidding - // signals and the allowed coalescing). + // `bidder_worklet` The pipe to communicate with the BidderWorklet. + // Closing the pipe will abort any in-progress loads destroy the worklet. The + // callback will be invoked on pipe destruction if it hasn't been already, + // since it's on the AuctionWorkletService pipe instead of the BidderWorklet + // pipe. // - // `auction_config` is the configuration provided by client JavaScript in - // the renderer in order to initiate the auction. + // `url_loader_factory` The URLLoaderFactory used to load the worklet script + // and trusted bidding signals. It's recommended that the implementation be + // restricted to exactly those URLs (keeping in mind query parameter usage + // for trusted bidding signals and the allowed coalescing). // - // `bidders` includes definitions of the interest groups that are selected to - // participate in this auction (initially added by client JS in the renderer, - // but managed by the browser's interest group store), as well as some - // bidding history collected by the interest group store. The bidding - // worklets of these groups will be fetched and executed. + // `bidding_interest_group` Definition of the interest group to fetch and + // execute the bidding script of for an ad auction (initially added by + // client JS in the renderer, but managed by the browser's interest group + // store), as well as some bidding history collected by the interest group + // store. // - // `browser_signals` signals from the browser about the auction that are the - // same for all worklets. + // `auction_signals_json` The JSON representation of the auction signals for + // the auction, specified by the publisher page and provided to bidder + // worklets competing in an auction. + // + // `per_buyer_signals_json` The JSON representation of the auction signals + // for the specific owner of this interest group, specified by the + // publisher page and provided to all interest groups with the same owner + // as the one specified `interest_group`. + // + // `browser_signal_top_window_origin` The origin of the top-level frame + // where the auction is running. + // + // `browser_signal_seller_origin` The origin of the seller script running + // the auction. + // + // `auction_start_time` The time the auction started, use to ensure the + // last win times provided to all worklets are relative to the same time. // // Returns: - // `render_url` URL of auction winning ad to render. - // An empty URL is used if there is no winner. + // `bid` If the worklet is successfully loaded and chooses to bid in the + // auction, contains information about the bid. Null otherwise. // - // `winning_interest_group_owner` owner of the winning interest group. - // An opaque origin if there is no winner. + // `errors` The various error messages to be used for debugging. These are too + // sensitive for the renderer to see. There may be errors even when a bid + // is offered, and there may be no errors when there's no bid. // - // `winning_interest_group_name` name of winning interest group. - // Empty if there is no winner. + // TODO(mmenke): Make BidderWorklets with the same URL reuseable, both + // between auctions, and within an auction, if two interest groups with the + // same owner share a script URL, and do the same for bidding signals, at + // least within an auction. + LoadBidderWorkletAndGenerateBid( + pending_receiver<BidderWorklet> bidder_worklet, + pending_remote<network.mojom.URLLoaderFactory> url_loader_factory, + BiddingInterestGroup bidding_interest_group, + string? auction_signals_json, + string? per_buyer_signals_json, + url.mojom.Origin browser_signal_top_window_origin, + url.mojom.Origin browser_signal_seller_origin, + mojo_base.mojom.Time auction_start_time) => ( + BidderWorkletBid? bid, + array<string> errors); + + // Attempts to load Javascript at the specified URL and loads a SellerWorklet. // - // `bidder_report` indicates if the winning buyer wishes to make a report, - // and the URL to use for that. - // `seller_report` indicates if the seller wishes to make a report, - // and the URL that the seller wanted fetched for that. // - // `errors` are various error messages to be used for debugging. These are too - // sensitive for the renderers to see. + // Arguments: + // `seller_worklet` The pipe to communicate with the SellerWorklet. Closing + // the pipe will abort any in-progress loads destroy the worklet. The + // callback will be invoked on seller worklet destruction if it hasn't + // already, since it's on the AuctionWorkletService pipe instead of the + // SellerWorklet pipe. // - // TODO(mmenke): May be good to make some way to share worklets between - // multiple auctions on the same page, but not auctions across pages. - // Could create separate top level AuctionWorkletService objects (using the - // same process), one for each tab, or something, to scope reused workets - // and bidding signals. - RunAuction(pending_remote<network.mojom.URLLoaderFactory> url_loader_factory, - blink.mojom.AuctionAdConfig auction_config, - array<BiddingInterestGroup> bidders, - BrowserSignals browser_signals) => ( - url.mojom.Url render_url, - url.mojom.Origin winning_interest_group_owner, - string winning_interest_group_name, - WinningBidderReport bidder_report, - SellerReport seller_report, - array<string> errors); + // `url_loader_factory` The UrlLoaderFactory used to load the worklet script. + // It's recommended that the implementation be restricted to only load the + // script URL. + // + // `script_source_url` is the URL of the seller worklet script. + // + // Returns: + // `success` is true if the worklet was successfully loaded. + // + // `errors` The various error messages to be used for debugging. These are too + // sensitive for the renderer to see. There may be errors even when the + // worklet is successfully loaded, and there may be no errors when the load + // fails. + LoadSellerWorklet( + pending_receiver<SellerWorklet> seller_worklet, + pending_remote<network.mojom.URLLoaderFactory> url_loader_factory, + url.mojom.Url script_source_url) => ( + bool success, + array<string> errors); };
diff --git a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom new file mode 100644 index 0000000..24c4a154 --- /dev/null +++ b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
@@ -0,0 +1,98 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module auction_worklet.mojom; + +import "mojo/public/mojom/base/time.mojom"; +import "services/network/public/mojom/url_loader_factory.mojom"; +import "third_party/blink/public/mojom/interest_group/interest_group_types.mojom"; +import "url/mojom/origin.mojom"; +import "url/mojom/url.mojom"; + +struct PreviousWin { + // Approximate time a particular group won an auction. + // + // TODO(mmenke): Provide this as an integer time since an auction was won, in + // seconds, to reduce time resolution of cross-site information provided to an + // untrusted service. + // + // TODO(https://crbug.com/1207135): Decide what to do when wins are + // "in the future" due to clock changes. + mojo_base.mojom.Time time; + + // The ad object returned by that group's bidding function with the winning + // bid. + string ad_json; +}; + +// Browser signals passed to the BidderWorklet's generateBid() method. Some +// fields are cached to pass to the reportWin() method as well. +struct BiddingBrowserSignals { + // How many times this interest group has been joined in the period history + // is maintained. + int32 join_count; + + // How many times this interest group has made bids in auctions. + int32 bid_count; + + // Previous times the group won auctions. + array<PreviousWin> prev_wins; +}; + +struct BiddingInterestGroup { + blink.mojom.InterestGroup group; // User JS specified, stored by browser. + BiddingBrowserSignals signals; // Collected by browser. +}; + +// The results of running a FLEDGE generateBid() script. +struct BidderWorkletBid { + // JSON string to be passed to the scoring function. + string ad; + + // Offered bid value. Always greater than 0. + double bid; + + // Render URL of the bid. + url.mojom.Url render_url; + + // How long it took to run the generateBid() script. + mojo_base.mojom.TimeDelta bid_duration; +}; + +// Manages the auction workflow for one loaded FLEDGE bidder worklet. +// See https://github.com/WICG/turtledove/blob/main/FLEDGE.md +// +// The BidderWorklet is functionally stateless, so methods are +// idempotent and can be called multiple times, in any order, for +// multiple auctions using the same worklet. There is no need to wait +// for one callback to be invoked before calling another method. +interface BidderWorklet { + // Calls the worklet's reportWin() method. May only be called + // LoadBidderWorkletAndGenerateBid() has completed successfully. + // + // `seller_signals_json` is a JSON representation of the object returned by + // the seller worklet's ReportResult method. + // + // `browser_signal_render_url` is the `render_url` returned by the + // BidderWorklet's generateBid() method, invoked as part of BidderWorklet + // creation. + // + // `browser_signal_ad_render_fingerprint` is a hash of the rendering URL, + // eventually to be replaced with a hash of the ad bundle, per spec. + // + // `report_url` is the URL to request to report the result of the auction + // to the bidder. It will be null if no reports are requested, or the + // report script fails to run. + // + // `errors` is an array of any errors that occurred while attempting + // to run the worklet's reportWin() method. These are too sensitive for + // the renderer to see. There may be errors even when a `report_url` is + // provided, and there may be no errors when there's no `report_url`. + ReportWin(string seller_signals_json, + url.mojom.Url browser_signal_render_url, + string browser_signal_ad_render_fingerprint, + double browser_signal_bid) => ( + url.mojom.Url? report_url, + array<string> errors); +};
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom new file mode 100644 index 0000000..00be49ed --- /dev/null +++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -0,0 +1,113 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module auction_worklet.mojom; + +import "mojo/public/mojom/base/time.mojom"; +import "services/network/public/mojom/url_loader_factory.mojom"; +import "third_party/blink/public/mojom/interest_group/interest_group_types.mojom"; +import "url/mojom/origin.mojom"; +import "url/mojom/url.mojom"; + +// Manages the auction workflow for one loaded FLEDGE seller worklet. +// See https://github.com/WICG/turtledove/blob/main/FLEDGE.md +// +// The SellerWorklet is functionally stateless, so methods are +// idempotent and can be called multiple times, in any order, for +// multiple auctions using the same worklet. There is no need to wait +// for one callback to be invoked before calling another method. +interface SellerWorklet { + // Calls the Javascript scoreAd() function to evaluate a bid. May only be + // called once the worklet has successfully completed loading. No data is + // leaked between consecutive invocations of this method, or between + // invocations of this method and ReportResult(). + // + // Arguments: + // `ad_metadata_json` JSON representation of the `ad` value returned by the + // BidWorklet that offered the bid. + // + // `bid` The numeric value of the bid offered by the BidWorklet. + // + // `auction_config` The configuration provided by client JavaScript in the + // renderer in order to initiate the auction. + // + // `browser_signal_top_window_origin` The top-level origin of the window + // running the auction. + // + // `browser_signal_interest_group_owner` The owner of the interest group + // that offered the bid. + // + // `browser_signal_ad_render_fingerprint` The hash of the rendering URL, + // eventually to be replaced with a hash of the ad bundle, per spec. + // + // `browser_signal_bidding_duration_msecs` is the duration the BiddingWorklet + // took to generate the bid. Taken as milliseconds to reduce granularity of + // timing information passed to an untrusted process. + // + // Returns: + // `score` Non-negative score the SellerWorklet assigns to the bid. A value + // of 0 indicates either an error running the script, or that the script + // indicated the bid should not be used. + // + // `errors` are various error messages to be used for debugging. These are too + // sensitive for the renderers to see. `errors` should not be assumed to be + // empty if `score` is positive, nor should it be assumed to be non-empty if + // `score` is 0. + ScoreAd(string ad_metadata_json, + double bid, + blink.mojom.AuctionAdConfig auction_config, + url.mojom.Origin browser_signal_top_window_origin, + url.mojom.Origin browser_signal_interest_group_owner, + string browser_signal_ad_render_fingerprint, + uint32 browser_signal_bidding_duration_msecs) => + (double score, array<string> errors); + + // Calls the Javascript reportResult() function to get the information needed + // to report the result of the auction to the seller. May only be called once + // the worklet has successfully completed loading. No data is leaked between + // consecutive invocations of this method, or between invocations of this + // method and ScoreAd(). + // + // Arguments: + // `auction_config` The configuration provided by client JavaScript in the + // renderer in order to initiate the auction. + // + // `browser_signal_top_window_origin` The top-level origin of the window + // running the auction. + // + // `browser_signal_interest_group_owner` The owner of the interest group + // that offered the winning bid. + // + // `browser_signal_render_url` The render URL provided by the winning bid. + // + // `browser_signal_ad_render_fingerprint` The hash of the rendering URL, + // eventually to be replaced with a hash of the ad bundle, per spec. + // + // `browser_signal_bid` The numeric value of the winning bid. + // + // `browser_signal_desirability` The score returned by ScoreAd for the + // the winning bid. + // + // Returns: + // `signals_for_winner` The value to pass to the winning bidder's + // ReportWin function, as a JSON string. Null if no value is provided. + // + // `report_url` The URL to request to report the result of the auction to the + // seller, if any. + // + // `errors` are various error messages to be used for debugging. These are too + // sensitive for the renderers to see. `errors` should not be assumed to be + // empty if the other values are populated, nor should it be assumed to be + // non-empty if the other values are null. + ReportResult(blink.mojom.AuctionAdConfig auction_config, + url.mojom.Origin browser_signal_top_window_origin, + url.mojom.Origin browser_signal_interest_group_owner, + url.mojom.Url browser_signal_render_url, + string browser_signal_ad_render_fingerprint, + double browser_signal_bid, + double browser_signal_desirability) => + (string? signals_for_winner, + url.mojom.Url? report_url, + array<string> error_msgs); +};
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc index b4b1668..cb20351 100644 --- a/content/services/auction_worklet/seller_worklet.cc +++ b/content/services/auction_worklet/seller_worklet.cc
@@ -17,10 +17,13 @@ #include "base/time/time.h" #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" #include "content/services/auction_worklet/report_bindings.h" #include "content/services/auction_worklet/worklet_loader.h" #include "gin/converter.h" #include "gin/dictionary.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" #include "url/gurl.h" #include "url/origin.h" #include "v8/include/v8.h" @@ -132,25 +135,39 @@ SellerWorklet::SellerWorklet( AuctionV8Helper* v8_helper, - network::mojom::URLLoaderFactory* url_loader_factory, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, const GURL& script_source_url, - LoadWorkletCallback load_worklet_callback) + mojom::AuctionWorkletService::LoadSellerWorkletCallback + load_worklet_callback) : v8_helper_(v8_helper), script_source_url_(script_source_url), load_worklet_callback_(std::move(load_worklet_callback)) { DCHECK(load_worklet_callback_); + + // Bind URLLoaderFactory. Remote is not needed after this method completes, + // since requests will continue after the URLLoaderFactory pipe has been + // closed, so no need to keep it around after requests have been issued. + mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory( + std::move(pending_url_loader_factory)); + worklet_loader_ = std::make_unique<WorkletLoader>( - url_loader_factory, script_source_url, v8_helper, + url_loader_factory.get(), script_source_url, v8_helper, base::BindOnce(&SellerWorklet::OnDownloadComplete, base::Unretained(this))); } -SellerWorklet::~SellerWorklet() = default; +SellerWorklet::~SellerWorklet() { + if (load_worklet_callback_) { + std::move(load_worklet_callback_) + .Run(false /* success */, std::vector<std::string>() /* errors */); + } +} void SellerWorklet::ScoreAd( const std::string& ad_metadata_json, double bid, - const blink::mojom::AuctionAdConfig& auction_config, + blink::mojom::AuctionAdConfigPtr auction_config, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_interest_group_owner, const std::string& browser_signal_ad_render_fingerprint, @@ -174,7 +191,7 @@ args.push_back(gin::ConvertToV8(isolate, bid)); - if (!AppendAuctionConfig(v8_helper_, context, auction_config, &args)) { + if (!AppendAuctionConfig(v8_helper_, context, *auction_config, &args)) { std::move(callback).Run(0 /* score */, std::vector<std::string>() /* errors */); return; @@ -233,7 +250,7 @@ } void SellerWorklet::ReportResult( - const blink::mojom::AuctionAdConfig& auction_config, + blink::mojom::AuctionAdConfigPtr auction_config, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_interest_group_owner, const GURL& browser_signal_render_url, @@ -257,7 +274,7 @@ v8::Context::Scope context_scope(context); std::vector<v8::Local<v8::Value>> args; - if (!AppendAuctionConfig(v8_helper_, context, auction_config, &args)) { + if (!AppendAuctionConfig(v8_helper_, context, *auction_config, &args)) { std::move(callback).Run(absl::nullopt /* signals_for_winner */, absl::nullopt /* report_url */, std::vector<std::string>() /* errors */);
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h index db1c4bb..7abd3c7 100644 --- a/content/services/auction_worklet/seller_worklet.h +++ b/content/services/auction_worklet/seller_worklet.h
@@ -12,6 +12,9 @@ #include "base/callback.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom-forward.h" +#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" +#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "services/network/public/mojom/url_loader_factory.mojom-forward.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom-forward.h" @@ -27,71 +30,40 @@ // Represents a seller worklet for FLEDGE // (https://github.com/WICG/turtledove/blob/main/FLEDGE.md). Loads and runs the // seller worklet's Javascript. -class SellerWorklet { +class SellerWorklet : public mojom::SellerWorklet { public: - using LoadWorkletCallback = - base::OnceCallback<void(bool success, - const std::vector<std::string>& errors)>; - - // Callback for ScoreAd(). On success, `score` is the positive score returned - // by the script. On failure, it's 0. `errors` is a vector of any errors that - // occurred while running the script. - using ScoreAdCallback = - base::OnceCallback<void(double score, - const std::vector<std::string>& errors)>; - - // Callback for ReportResult(). - // - // `signals_for_winner` is JSON data as a string that should be sent to the - // winning bidder worklet's reportWin() function. It's empty if the script - // failed to run or threw an exception, and "null" if the return value wasn't - // a valid JSON object. - // - // `report_url` is the report URL provided by the script, if one is provided. - // nullopt on failure, or if no report URL is provided. - // - // `errors` is a vector of any errors that occurred while running the - // script. - using ReportResultCallback = base::OnceCallback<void( - const absl::optional<std::string>& signals_for_winner, - const absl::optional<GURL>& report_url, - const std::vector<std::string>& errors)>; - // Starts loading the worklet script on construction. Callback will be invoked // asynchronously once the data has been fetched or an error has occurred. // Must be destroyed before `v8_helper`. SellerWorklet(AuctionV8Helper* v8_helper, - network::mojom::URLLoaderFactory* url_loader_factory, + mojo::PendingRemote<network::mojom::URLLoaderFactory> + pending_url_loader_factory, const GURL& script_source_url, - LoadWorkletCallback load_worklet_callback); + mojom::AuctionWorkletService::LoadSellerWorkletCallback + load_worklet_callback); + explicit SellerWorklet(const SellerWorklet&) = delete; SellerWorklet& operator=(const SellerWorklet&) = delete; - ~SellerWorklet(); - // Calls scoreAd(), and invokes passed in callback asynchronously with the - // resulting score. May only be called once the worklet has successfully - // completed loaded. No data is leaked between consecutive invocations of this - // method, or between invocations of this method and ReportResult(). + ~SellerWorklet() override; + + // mojom::SellerWorklet implementation: void ScoreAd(const std::string& ad_metadata_json, double bid, - const blink::mojom::AuctionAdConfig& auction_config, + blink::mojom::AuctionAdConfigPtr auction_config, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_interest_group_owner, const std::string& browser_signal_ad_render_fingerprint, uint32_t browser_signal_bidding_duration_msecs, - ScoreAdCallback callback); - - // Calls reportResult(), and invokes passed in callback asynchronously with - // the reporting information. May only be called once the worklet has - // successfully loaded. - void ReportResult(const blink::mojom::AuctionAdConfig& auction_config, + ScoreAdCallback callback) override; + void ReportResult(blink::mojom::AuctionAdConfigPtr auction_config, const url::Origin& browser_signal_top_window_origin, const url::Origin& browser_signal_interest_group_owner, const GURL& browser_signal_render_url, const std::string& browser_signal_ad_render_fingerprint, double browser_signal_bid, double browser_signal_desirability, - ReportResultCallback callback); + ReportResultCallback callback) override; private: void OnDownloadComplete( @@ -103,7 +75,8 @@ const GURL script_source_url_; std::unique_ptr<WorkletLoader> worklet_loader_; - LoadWorkletCallback load_worklet_callback_; + mojom::AuctionWorkletService::LoadSellerWorkletCallback + load_worklet_callback_; // Compiled script, not bound to any context. Can be repeatedly bound to // different context and executed, without persisting any state. std::unique_ptr<v8::Global<v8::UnboundScript>> worklet_script_;
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc index f3b618c..97886b3 100644 --- a/content/services/auction_worklet/seller_worklet_unittest.cc +++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -16,6 +16,7 @@ #include "content/services/auction_worklet/auction_v8_helper.h" #include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h" #include "content/services/auction_worklet/worklet_test_util.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/http/http_status_code.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock-matchers.h" @@ -121,12 +122,12 @@ base::RunLoop run_loop; seller_worket->ScoreAd( - ad_metadata_, bid_, *auction_config_, browser_signal_top_window_origin_, - browser_signal_interest_group_owner_, + ad_metadata_, bid_, auction_config_.Clone(), + browser_signal_top_window_origin_, browser_signal_interest_group_owner_, browser_signal_ad_render_fingerprint_, browser_signal_bidding_duration_msecs_, base::BindLambdaForTesting( - [&run_loop, &expected_score, expected_errors]( + [&run_loop, &expected_score, &expected_errors]( double score, const std::vector<std::string>& errors) { EXPECT_EQ(expected_score, score); EXPECT_EQ(expected_errors, errors); @@ -176,7 +177,7 @@ base::RunLoop run_loop; seller_worket->ReportResult( - *auction_config_, browser_signal_top_window_origin_, + auction_config_.Clone(), browser_signal_top_window_origin_, browser_signal_interest_group_owner_, browser_signal_render_url_, browser_signal_ad_render_fingerprint_, bid_, browser_signal_desireability_, @@ -195,24 +196,30 @@ } // Create a SellerWorklet, waiting for the URLLoader to complete. Returns - // nullptr on failure. - std::unique_ptr<SellerWorklet> CreateWorklet() { + // a null Remote on failure. + mojo::Remote<mojom::SellerWorklet> CreateWorklet() { CHECK(!load_script_run_loop_); + mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; + url_loader_factory_.Clone( + url_loader_factory.InitWithNewPipeAndPassReceiver()); + create_worklet_succeeded_ = false; - auto seller_worket = std::make_unique<SellerWorklet>( - &v8_helper_, &url_loader_factory_, url_, - base::BindOnce(&SellerWorkletTest::CreateWorkletCallback, - base::Unretained(this))); + mojo::Remote<mojom::SellerWorklet> seller_worklet; + mojo::MakeSelfOwnedReceiver( + std::make_unique<SellerWorklet>( + &v8_helper_, std::move(url_loader_factory), url_, + base::BindOnce(&SellerWorkletTest::CreateWorkletCallback, + base::Unretained(this))), + seller_worklet.BindNewPipeAndPassReceiver()); load_script_run_loop_ = std::make_unique<base::RunLoop>(); load_script_run_loop_->Run(); load_script_run_loop_.reset(); if (!create_worklet_succeeded_) - return nullptr; - return seller_worket; + return mojo::Remote<mojom::SellerWorklet>(); + return seller_worklet; } - protected: void CreateWorkletCallback(bool success, const std::vector<std::string>& errors) { create_worklet_succeeded_ = success; @@ -222,6 +229,7 @@ load_script_run_loop_->Quit(); } + protected: base::test::TaskEnvironment task_environment_; const GURL url_ = GURL("https://url.test/"); @@ -251,6 +259,30 @@ AuctionV8Helper v8_helper_; }; +// Test the case the SellerWorklet pipe is closed before invoking the +// LoadSellerWorkletCallback. The LoadSellerWorkletCallback should be invoked, +// and there should be no Mojo exception due to destroying the creation callback +// without invoking it. +TEST_F(SellerWorkletTest, PipeClosed) { + mojo::Remote<mojom::SellerWorklet> seller_worklet; + mojo::PendingReceiver<network::mojom::URLLoaderFactory> + url_loader_factory_receiver; + + mojo::MakeSelfOwnedReceiver( + std::make_unique<SellerWorklet>( + &v8_helper_, + url_loader_factory_receiver.InitWithNewPipeAndPassRemote(), url_, + base::BindOnce(&SellerWorkletTest::CreateWorkletCallback, + base::Unretained(this))), + seller_worklet.BindNewPipeAndPassReceiver()); + load_script_run_loop_ = std::make_unique<base::RunLoop>(); + seller_worklet.reset(); + + load_script_run_loop_->Run(); + load_script_run_loop_.reset(); + EXPECT_FALSE(create_worklet_succeeded_); +} + TEST_F(SellerWorkletTest, NetworkError) { url_loader_factory_.AddResponse(url_.spec(), CreateBasicSellAdScript(), net::HTTP_NOT_FOUND); @@ -654,7 +686,7 @@ for (int j = 0; j < 2; ++j) { base::RunLoop run_loop; seller_worket->ScoreAd( - ad_metadata_, bid_, *auction_config_, + ad_metadata_, bid_, auction_config_.Clone(), browser_signal_top_window_origin_, browser_signal_interest_group_owner_, browser_signal_ad_render_fingerprint_, @@ -672,7 +704,7 @@ for (int j = 0; j < 2; ++j) { base::RunLoop run_loop; seller_worket->ReportResult( - *auction_config_, browser_signal_top_window_origin_, + auction_config_.Clone(), browser_signal_top_window_origin_, browser_signal_interest_group_owner_, browser_signal_render_url_, browser_signal_ad_render_fingerprint_, bid_, browser_signal_desireability_,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 6244f57..a68b7f49 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1040,6 +1040,7 @@ "../browser/browsing_data/same_site_data_remover_impl_browsertest.cc", "../browser/child_process_launcher_browsertest.cc", "../browser/child_process_security_policy_browsertest.cc", + "../browser/compute_pressure/compute_pressure_origin_trial_browsertest.cc", "../browser/content_index/content_index_browsertest.cc", "../browser/content_security_policy_browsertest.cc", "../browser/conversions/conversion_internals_browsertest.cc", @@ -1954,6 +1955,7 @@ "../browser/indexed_db/mock_mojo_indexed_db_callbacks.h", "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc", "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h", + "../browser/interest_group/auction_runner_unittest.cc", "../browser/interest_group/auction_url_loader_factory_proxy_unittest.cc", "../browser/interest_group/interest_group_storage_unittest.cc", "../browser/loader/cors_origin_pattern_setter_unittest.cc", @@ -2346,6 +2348,7 @@ "//content/public/common:trust_tokens_mojo_bindings", "//content/public/renderer", "//content/renderer:for_content_tests", + "//content/services/auction_worklet", "//content/services/auction_worklet:tests", "//content/services/auction_worklet/public/mojom", "//crypto",
diff --git a/content/test/data/compute_pressure/no_token.html b/content/test/data/compute_pressure/no_token.html new file mode 100644 index 0000000..47ff433 --- /dev/null +++ b/content/test/data/compute_pressure/no_token.html
@@ -0,0 +1,3 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Compute Pressure API No Origin Trial Test</title>
diff --git a/content/test/data/compute_pressure/valid_token.html b/content/test/data/compute_pressure/valid_token.html new file mode 100644 index 0000000..4512f81 --- /dev/null +++ b/content/test/data/compute_pressure/valid_token.html
@@ -0,0 +1,7 @@ +<!doctype html> +<meta charset="utf-8"> +<!-- The OT token below expires in 2033. + Regenerate this token with the command: + generate_token.py --expire-timestamp=2000000000 https://example.test ComputePressure --> +<meta http-equiv="origin-trial" content="A/jtk5npXPKyDrNo9oTFvtpkxme5321eVz7rRB35qNSG+U00gtajlCmSfhxTxUDuAb0umALAsiXoKIfMHl3mnQMAAABaeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiQ29tcHV0ZVByZXNzdXJlIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9"> +<title>Compute Pressure API Origin Trial Test</title>
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py index a5c9fff..121b8aa0 100644 --- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py +++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -464,7 +464,6 @@ 'OES_vertex_array_object', 'WEBGL_compressed_texture_etc1', 'WEBGL_debug_renderer_info', - 'WEBGL_debug_shaders', 'WEBGL_depth_texture', 'WEBKIT_WEBGL_depth_texture', 'WEBGL_draw_buffers',
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py index 27baa52..0be2686 100644 --- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py +++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -50,7 +50,7 @@ arg_obj = args[0] tab.Navigate(url) tab.action_runner.WaitForJavaScriptCondition( - 'document.readyState == "complete"', timeout=5) + 'document.readyState == "complete"') tab.EvaluateJavaScript('TEST.run(' + str(arg_obj) + ')') tab.action_runner.WaitForJavaScriptCondition('TEST.finished', timeout=60) if not tab.EvaluateJavaScript('TEST.success'):
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc index 50f2eac..3147400 100644 --- a/device/fido/cable/fido_cable_discovery.cc +++ b/device/fido/cable/fido_cable_discovery.cc
@@ -562,6 +562,8 @@ absl::optional<FidoCableDiscovery::V1DiscoveryDataAndEID> FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) { + const std::vector<uint8_t>* const service_data = + device->GetServiceDataForUUID(CableAdvertisementUUID()); absl::optional<CableEidArray> maybe_eid_from_service_data = MaybeGetEidFromServiceData(device); std::vector<CableEidArray> uuids = GetUUIDs(device); @@ -592,6 +594,8 @@ GetCableDiscoveryDataFromAuthenticatorEid(*maybe_eid_from_service_data); FIDO_LOG(DEBUG) << " Service data: " << ResultDebugString(*maybe_eid_from_service_data, result); + } else if (service_data) { + FIDO_LOG(DEBUG) << " Service data: " << base::HexEncode(*service_data); } else { FIDO_LOG(DEBUG) << " Service data: <none>"; } @@ -622,11 +626,12 @@ } } - // Try all combinations of 16- and 4-byte UUIDs to form 20-byte advert - // payloads. (We don't know if something in the BLE stack might add other - // short UUIDs to a BLE advert message). if (advert_callback_) { std::array<uint8_t, 16 + 4> v2_advert; + + // Try all combinations of 16- and 4-byte UUIDs to form 20-byte advert + // payloads. (We don't know if something in the BLE stack might add other + // short UUIDs to a BLE advert message). for (const auto& uuid128 : uuid128s) { static_assert(EXTENT(uuid128) == 16, ""); memcpy(v2_advert.data(), uuid128.data(), 16); @@ -637,6 +642,11 @@ advert_callback_.Run(v2_advert); } } + + if (service_data && service_data->size() == v2_advert.size()) { + memcpy(v2_advert.data(), service_data->data(), v2_advert.size()); + advert_callback_.Run(v2_advert); + } } auto observed_data = std::make_unique<ObservedDeviceData>(); @@ -650,7 +660,7 @@ // static absl::optional<CableEidArray> FidoCableDiscovery::MaybeGetEidFromServiceData( const BluetoothDevice* device) { - const auto* service_data = + const std::vector<uint8_t>* service_data = device->GetServiceDataForUUID(CableAdvertisementUUID()); if (!service_data) { return absl::nullopt;
diff --git a/docs/accessibility/select_to_speak.md b/docs/accessibility/select_to_speak.md index 44641f6f..92a2589 100644 --- a/docs/accessibility/select_to_speak.md +++ b/docs/accessibility/select_to_speak.md
@@ -47,7 +47,7 @@ - An event handler, ash/events/select_to_speak_event_handler.h -- The status tray button, ash/system/accessibility/select_to_speak_tray.h +- The status tray button, ash/system/accessibility/select_to_speak/select_to_speak_tray.h - Floating panel, system/accessibility/select_to_speak_menu_bubble_controller.h @@ -202,7 +202,7 @@ #### Floating control panel The panel is implemented as a native ASH component -[select_to_speak_menu_bubble_controller.h](https://source.chromium.org/chromium/chromium/src/+/master:ash/system/accessibility/select_to_speak_menu_bubble_controller.h). +[select_to_speak_menu_bubble_controller.h](https://source.chromium.org/chromium/chromium/src/+/main:ash/system/accessibility/select_to_speak/select_to_speak_menu_bubble_controller.h). Similar to focus rings, the STS component extension communicates with the panel via the `chrome.accessibilityPrivate` API. The `chrome.accessibilityPrivate.updateSelectToSpeakPanel` API controls the @@ -262,7 +262,7 @@ Users can navigate to adjacent paragraphs from the current block parent when Select-to-speak is active. A 'paragraph' is any block element as defined by -[ParagraphUtils.isBlock](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js) +[ParagraphUtils.isBlock](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js) and the navigation occurs in DOM-order. #### Sentence navigation @@ -270,7 +270,7 @@ Paragraphs are split into sentences based on the `sentenceStarts` property of an AutomationNode. Users can skip to previous and next sentences using similar technique as pause/resume (`stop` then `speak` with trimmed text). See -[sentence_utils.js](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/resources/chromeos/accessibility/select_to_speak/sentence_utils.js) +[sentence_utils.js](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/chromeos/accessibility/select_to_speak/sentence_utils.js) for logic on breaking node groups into sentences. #### Reading speed @@ -316,4 +316,4 @@ [go/chrome-sts-sentences-and-words](go/chrome-sts-sentences-and-words) and [go/chromeos-sts-highlight](go/chromeos-sts-highlight) -- Navigation features, [go/enhanced-sts-dd](go/enhanced-sts-dd) \ No newline at end of file +- Navigation features, [go/enhanced-sts-dd](go/enhanced-sts-dd)
diff --git a/extensions/browser/api/app_window/app_window_apitest.cc b/extensions/browser/api/app_window/app_window_apitest.cc index d4e412fa..20e26ce 100644 --- a/extensions/browser/api/app_window/app_window_apitest.cc +++ b/extensions/browser/api/app_window/app_window_apitest.cc
@@ -66,67 +66,65 @@ #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(AppWindowApiTest, MAYBE_OnMinimizedEvent) { - EXPECT_TRUE(RunExtensionTest({.name = "platform_apps/windows_api_properties", - .custom_arg = "minimized"})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_properties", + {.custom_arg = "minimized"})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, MAYBE_OnMaximizedEvent) { - EXPECT_TRUE(RunExtensionTest({.name = "platform_apps/windows_api_properties", - .custom_arg = "maximized"})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_properties", + {.custom_arg = "maximized"})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, MAYBE_OnRestoredEvent) { - EXPECT_TRUE(RunExtensionTest({.name = "platform_apps/windows_api_properties", - .custom_arg = "restored"})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_properties", + {.custom_arg = "restored"})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, OnBoundsChangedEvent) { - EXPECT_TRUE(RunExtensionTest({.name = "platform_apps/windows_api_properties", - .custom_arg = "boundsChanged"})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_properties", + {.custom_arg = "boundsChanged"})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlwaysOnTopWithPermissions) { EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_always_on_top/has_permissions", - .launch_as_platform_app = true})) + "platform_apps/windows_api_always_on_top/has_permissions", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlwaysOnTopWithOldPermissions) { EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_always_on_top/has_old_permissions", - .launch_as_platform_app = true})) + "platform_apps/windows_api_always_on_top/has_old_permissions", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlwaysOnTopNoPermissions) { - EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_always_on_top/no_permissions", - .launch_as_platform_app = true})) + EXPECT_TRUE( + RunExtensionTest("platform_apps/windows_api_always_on_top/no_permissions", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, Get) { - EXPECT_TRUE(RunExtensionTest({.name = "platform_apps/windows_api_get", - .launch_as_platform_app = true})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_get", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, SetShapeHasPerm) { - EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_shape/has_permission", - .launch_as_platform_app = true})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_shape/has_permission", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, SetShapeNoPerm) { - EXPECT_TRUE( - RunExtensionTest({.name = "platform_apps/windows_api_shape/no_permission", - .launch_as_platform_app = true})) + EXPECT_TRUE(RunExtensionTest("platform_apps/windows_api_shape/no_permission", + {.launch_as_platform_app = true})) << message_; } @@ -156,67 +154,65 @@ #endif // OS_WIN #endif // USE_AURA && !(OS_LINUX || IS_CHROMEOS_LACROS) - EXPECT_TRUE( - RunExtensionTest({.name = test_dir, .launch_as_platform_app = true})) + EXPECT_TRUE(RunExtensionTest(test_dir, {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlphaEnabledNoPermissions) { - EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_alpha_enabled/no_permissions", - .launch_as_platform_app = true})) + EXPECT_TRUE( + RunExtensionTest("platform_apps/windows_api_alpha_enabled/no_permissions", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlphaEnabledInStable) { extensions::ScopedCurrentChannel channel(version_info::Channel::STABLE); - EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_alpha_enabled/in_stable", - .launch_as_platform_app = true}, - // Ignore manifest warnings because the extension will not load at all - // in stable. - {.ignore_manifest_warnings = true})) + EXPECT_TRUE( + RunExtensionTest("platform_apps/windows_api_alpha_enabled/in_stable", + {.launch_as_platform_app = true}, + // Ignore manifest warnings because the extension will + // not load at all in stable. + {.ignore_manifest_warnings = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlphaEnabledWrongFrameType) { EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_alpha_enabled/wrong_frame_type", - .launch_as_platform_app = true})) + "platform_apps/windows_api_alpha_enabled/wrong_frame_type", + {.launch_as_platform_app = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, VisibleOnAllWorkspacesInStable) { extensions::ScopedCurrentChannel channel(version_info::Channel::STABLE); EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_visible_on_all_workspaces/in_stable", - .launch_as_platform_app = true})) + "platform_apps/windows_api_visible_on_all_workspaces/in_stable", + {.launch_as_platform_app = true})) << message_; } #if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(AppWindowApiTest, ImeWindowHasPermissions) { EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_ime/has_permissions_whitelisted"}, + "platform_apps/windows_api_ime/has_permissions_whitelisted", {}, {.load_as_component = true})) << message_; EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_ime/has_permissions_platform_app", - .launch_as_platform_app = true}, - {.ignore_manifest_warnings = true})) + "platform_apps/windows_api_ime/has_permissions_platform_app", + {.launch_as_platform_app = true}, {.ignore_manifest_warnings = true})) << message_; } IN_PROC_BROWSER_TEST_F(AppWindowApiTest, ImeWindowNoPermissions) { EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_ime/no_permissions_whitelisted"}, + "platform_apps/windows_api_ime/no_permissions_whitelisted", {}, {.load_as_component = true})) << message_; EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_ime/no_permissions_platform_app", - .launch_as_platform_app = true})) + "platform_apps/windows_api_ime/no_permissions_platform_app", + {.launch_as_platform_app = true})) << message_; } @@ -227,7 +223,7 @@ "jkghodnilhceideoidjikpgommlajknk"); EXPECT_TRUE(RunExtensionTest( - {.name = "platform_apps/windows_api_ime/forced_app_mode_not_fullscreen"}, + "platform_apps/windows_api_ime/forced_app_mode_not_fullscreen", {}, {.load_as_component = true})) << message_; }
diff --git a/extensions/browser/api/audio/audio_api.cc b/extensions/browser/api/audio/audio_api.cc index cd96c7b..ef792c20 100644 --- a/extensions/browser/api/audio/audio_api.cc +++ b/extensions/browser/api/audio/audio_api.cc
@@ -91,7 +91,7 @@ auto event = std::make_unique<Event>(events::AUDIO_ON_DEVICE_CHANGED, audio::OnDeviceChanged::kEventName, - std::make_unique<base::ListValue>()); + std::vector<base::Value>()); event->will_dispatch_callback = base::BindRepeating(&CanReceiveDeprecatedAudioEvent); event_router->BroadcastEvent(std::move(event));
diff --git a/extensions/browser/api/clipboard/clipboard_api.cc b/extensions/browser/api/clipboard/clipboard_api.cc index 633d2495..18e4e50 100644 --- a/extensions/browser/api/clipboard/clipboard_api.cc +++ b/extensions/browser/api/clipboard/clipboard_api.cc
@@ -44,7 +44,7 @@ std::unique_ptr<Event> event( new Event(events::CLIPBOARD_ON_CLIPBOARD_DATA_CHANGED, clipboard::OnClipboardDataChanged::kEventName, - std::make_unique<base::ListValue>())); + std::vector<base::Value>())); router->BroadcastEvent(std::move(event)); } }
diff --git a/extensions/browser/api/declarative_net_request/action_tracker.cc b/extensions/browser/api/declarative_net_request/action_tracker.cc index 969fee0..db5f31bc 100644 --- a/extensions/browser/api/declarative_net_request/action_tracker.cc +++ b/extensions/browser/api/declarative_net_request/action_tracker.cc
@@ -431,8 +431,9 @@ matched_rule_info_debug.rule = std::move(matched_rule); matched_rule_info_debug.request = std::move(request_details); - auto args = std::make_unique<base::ListValue>(); - args->Append(matched_rule_info_debug.ToValue()); + std::vector<base::Value> args; + args.push_back( + base::Value::FromUniquePtrValue(matched_rule_info_debug.ToValue())); auto event = std::make_unique<Event>( events::DECLARATIVE_NET_REQUEST_ON_RULE_MATCHED_DEBUG,
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc index e9abff54..84d1b025 100644 --- a/extensions/browser/api/management/management_api.cc +++ b/extensions/browser/api/management/management_api.cc
@@ -1094,12 +1094,12 @@ const char* event_name) { if (!extension->ShouldExposeViaManagementAPI()) return; - std::unique_ptr<base::ListValue> args(new base::ListValue()); + std::vector<base::Value> args; if (event_name == management::OnUninstalled::kEventName) { - args->AppendString(extension->id()); + args.push_back(base::Value(extension->id())); } else { - args->Append( - CreateExtensionInfo(nullptr, *extension, browser_context_).ToValue()); + args.push_back(base::Value::FromUniquePtrValue( + CreateExtensionInfo(nullptr, *extension, browser_context_).ToValue())); } EventRouter::Get(browser_context_)
diff --git a/extensions/browser/api/printer_provider/printer_provider_api.cc b/extensions/browser/api/printer_provider/printer_provider_api.cc index 9bacc4d..e828002 100644 --- a/extensions/browser/api/printer_provider/printer_provider_api.cc +++ b/extensions/browser/api/printer_provider/printer_provider_api.cc
@@ -528,10 +528,10 @@ // be needed later on. int request_id = pending_get_printers_requests_.Add(callback); - std::unique_ptr<base::ListValue> internal_args(new base::ListValue); + std::vector<base::Value> internal_args; // Request id is not part of the public API, but it will be massaged out in // custom bindings. - internal_args->AppendInteger(request_id); + internal_args.push_back(base::Value(request_id)); std::unique_ptr<Event> event( new Event(events::PRINTER_PROVIDER_ON_GET_PRINTERS_REQUESTED, @@ -567,11 +567,11 @@ int request_id = pending_capability_requests_[extension_id].Add(std::move(callback)); - std::unique_ptr<base::ListValue> internal_args(new base::ListValue); + std::vector<base::Value> internal_args; // Request id is not part of the public API, but it will be massaged out in // custom bindings. - internal_args->AppendInteger(request_id); - internal_args->AppendString(internal_printer_id); + internal_args.push_back(base::Value(request_id)); + internal_args.push_back(base::Value(internal_printer_id)); std::unique_ptr<Event> event( new Event(events::PRINTER_PROVIDER_ON_GET_CAPABILITY_REQUESTED, @@ -612,11 +612,11 @@ int request_id = pending_print_requests_[extension_id].Add( std::move(job), std::move(callback)); - std::unique_ptr<base::ListValue> internal_args(new base::ListValue); + std::vector<base::Value> internal_args; // Request id is not part of the public API and it will be massaged out in // custom bindings. - internal_args->AppendInteger(request_id); - internal_args->Append(print_job.ToValue()); + internal_args.push_back(base::Value(request_id)); + internal_args.push_back(base::Value::FromUniquePtrValue(print_job.ToValue())); std::unique_ptr<Event> event( new Event(events::PRINTER_PROVIDER_ON_PRINT_REQUESTED, api::printer_provider::OnPrintRequested::kEventName, @@ -650,11 +650,12 @@ api::usb::Device api_device; UsbDeviceManager::Get(browser_context_)->GetApiDevice(device, &api_device); - std::unique_ptr<base::ListValue> internal_args(new base::ListValue()); + std::vector<base::Value> internal_args; // Request id is not part of the public API and it will be massaged out in // custom bindings. - internal_args->AppendInteger(request_id); - internal_args->Append(api_device.ToValue()); + internal_args.push_back(base::Value(request_id)); + internal_args.push_back( + base::Value::FromUniquePtrValue(api_device.ToValue())); std::unique_ptr<Event> event( new Event(events::PRINTER_PROVIDER_ON_GET_USB_PRINTER_INFO_REQUESTED, api::printer_provider::OnGetUsbPrinterInfoRequested::kEventName,
diff --git a/extensions/browser/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc index ba976db..cba8db7 100644 --- a/extensions/browser/api/runtime/runtime_api.cc +++ b/extensions/browser/api/runtime/runtime_api.cc
@@ -137,10 +137,9 @@ } } - std::unique_ptr<base::ListValue> event_args(new base::ListValue()); std::unique_ptr<Event> event(new Event(events::RUNTIME_ON_STARTUP, runtime::OnStartup::kEventName, - std::move(event_args))); + std::vector<base::Value>())); EventRouter::Get(browser_context) ->DispatchEventToExtension(extension_id, std::move(event)); } @@ -450,17 +449,17 @@ return; } - std::unique_ptr<base::ListValue> event_args(new base::ListValue()); - std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue()); + std::vector<base::Value> event_args; + base::Value info(base::Value::Type::DICTIONARY); if (old_version.IsValid()) { - info->SetString(kInstallReason, kInstallReasonUpdate); - info->SetString(kInstallPreviousVersion, old_version.GetString()); + info.SetStringKey(kInstallReason, kInstallReasonUpdate); + info.SetStringKey(kInstallPreviousVersion, old_version.GetString()); } else if (chrome_updated) { - info->SetString(kInstallReason, kInstallReasonChromeUpdate); + info.SetStringKey(kInstallReason, kInstallReasonChromeUpdate); } else { - info->SetString(kInstallReason, kInstallReasonInstall); + info.SetStringKey(kInstallReason, kInstallReasonInstall); } - event_args->Append(std::move(info)); + event_args.push_back(std::move(info)); EventRouter* event_router = EventRouter::Get(context); DCHECK(event_router); std::unique_ptr<Event> event(new Event(events::RUNTIME_ON_INSTALLED, @@ -478,13 +477,12 @@ for (ExtensionSet::const_iterator i = dependents->begin(); i != dependents->end(); i++) { - std::unique_ptr<base::ListValue> sm_event_args(new base::ListValue()); - std::unique_ptr<base::DictionaryValue> sm_info( - new base::DictionaryValue()); - sm_info->SetString(kInstallReason, kInstallReasonSharedModuleUpdate); - sm_info->SetString(kInstallPreviousVersion, old_version.GetString()); - sm_info->SetString(kInstallId, extension_id); - sm_event_args->Append(std::move(sm_info)); + std::vector<base::Value> sm_event_args; + base::Value sm_info(base::Value::Type::DICTIONARY); + sm_info.SetStringKey(kInstallReason, kInstallReasonSharedModuleUpdate); + sm_info.SetStringKey(kInstallPreviousVersion, old_version.GetString()); + sm_info.SetStringKey(kInstallId, extension_id); + sm_event_args.push_back(std::move(sm_info)); std::unique_ptr<Event> sm_event(new Event( events::RUNTIME_ON_INSTALLED, runtime::OnInstalled::kEventName, std::move(sm_event_args))); @@ -504,8 +502,8 @@ if (!system) return; - std::unique_ptr<base::ListValue> args(new base::ListValue); - args->Append(manifest->CreateDeepCopy()); + std::vector<base::Value> args; + args.push_back(manifest->Clone()); EventRouter* event_router = EventRouter::Get(context); DCHECK(event_router); std::unique_ptr<Event> event(new Event(events::RUNTIME_ON_UPDATE_AVAILABLE, @@ -521,12 +519,12 @@ if (!system) return; - std::unique_ptr<base::ListValue> args(new base::ListValue); EventRouter* event_router = EventRouter::Get(context); DCHECK(event_router); - std::unique_ptr<Event> event(new Event( - events::RUNTIME_ON_BROWSER_UPDATE_AVAILABLE, - runtime::OnBrowserUpdateAvailable::kEventName, std::move(args))); + std::unique_ptr<Event> event( + new Event(events::RUNTIME_ON_BROWSER_UPDATE_AVAILABLE, + runtime::OnBrowserUpdateAvailable::kEventName, + std::vector<base::Value>())); event_router->BroadcastEvent(std::move(event)); }
diff --git a/extensions/browser/api/storage/storage_frontend.cc b/extensions/browser/api/storage/storage_frontend.cc index 866fb1c..5f28f3d6 100644 --- a/extensions/browser/api/storage/storage_frontend.cc +++ b/extensions/browser/api/storage/storage_frontend.cc
@@ -89,9 +89,9 @@ // Event for each storage(sync, local, managed). if (event_router->ExtensionHasEventListener( extension_id, api::storage::OnChanged::kEventName)) { - std::unique_ptr<base::ListValue> args(new base::ListValue()); - args->Append(changes.Clone()); - args->AppendString(namespace_string); + std::vector<base::Value> args; + args.push_back(changes.Clone()); + args.push_back(base::Value(namespace_string)); std::unique_ptr<Event> event( new Event(events::STORAGE_ON_CHANGED, api::storage::OnChanged::kEventName, std::move(args))); @@ -103,8 +103,8 @@ base::StringPrintf("storage.%s.onChanged", namespace_string.c_str()); if (event_router->ExtensionHasEventListener(extension_id, area_event_name)) { - auto args = std::make_unique<base::ListValue>(); - args->Append(changes.Clone()); + std::vector<base::Value> args; + args.push_back(changes.Clone()); auto event = std::make_unique<Event>(StorageAreaToEventHistogram(storage_area), area_event_name, std::move(args));
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index d1bf4e3..f9b8f149 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc
@@ -1038,11 +1038,6 @@ Event::Event(events::HistogramValue histogram_value, const std::string& event_name, - std::unique_ptr<base::ListValue> event_args) - : Event(histogram_value, event_name, std::move(event_args), nullptr) {} - -Event::Event(events::HistogramValue histogram_value, - const std::string& event_name, std::vector<base::Value> event_args, content::BrowserContext* restrict_to_browser_context) : Event(histogram_value,
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h index 5507c9f..4a89090 100644 --- a/extensions/browser/event_router.h +++ b/extensions/browser/event_router.h
@@ -511,10 +511,6 @@ Event(events::HistogramValue histogram_value, const std::string& event_name, std::vector<base::Value> event_args); - // TODO(crbug.com/1139221): Remove this deprecated ctor and use the one above. - Event(events::HistogramValue histogram_value, - const std::string& event_name, - std::unique_ptr<base::ListValue> event_args); Event(events::HistogramValue histogram_value, const std::string& event_name,
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc index cbf71af..b25f70f 100644 --- a/extensions/browser/extension_protocols.cc +++ b/extensions/browser/extension_protocols.cc
@@ -302,8 +302,7 @@ // Dedicated Worker (with PlzDedicatedWorker) and Shared Worker main scripts // can be loaded with extension URLs in browser process. // Service Worker and the imported scripts can be loaded with extension URLs - // in browser process during update check when - // ServiceWorkerImportedScriptUpdateCheck is enabled. + // in browser process when PlzServiceWorker is enabled or during update check. if (child_id == content::ChildProcessHost::kInvalidUniqueID && (blink::IsRequestDestinationFrame(destination) || (base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker) &&
diff --git a/extensions/browser/extension_protocols.h b/extensions/browser/extension_protocols.h index eaaac71..a6410e6d 100644 --- a/extensions/browser/extension_protocols.h +++ b/extensions/browser/extension_protocols.h
@@ -61,8 +61,8 @@ // Creates a new network::mojom::URLLoaderFactory implementation suitable for // handling service worker main/imported script requests initiated by the -// browser process to extension URLs during service worker update check when -// ServiceWorkerImportedScriptUpdateCheck is enabled. +// browser process to extension URLs when PlzServiceWorker is enabled or during +// service worker update check. mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateExtensionServiceWorkerScriptURLLoaderFactory( content::BrowserContext* browser_context);
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 8422479b..688f60e 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -183,7 +183,8 @@ "contexts": ["webui"], "matches": [ "chrome://feedback/*", - "chrome://cast-feedback/*" + "chrome://cast-feedback/*", + "chrome://os-feedback/*" ] } ],
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 6fe1f6b2..a9e1b277 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "extensions/common/extension_features.h" +#include "base/feature_list.h" namespace extensions_features { @@ -16,6 +17,12 @@ const base::Feature kDisableMalwareExtensionsRemotely{ "DisableMalwareExtensionsRemotely", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls whether we disable extensions that are marked as policy violation +// by the Omaha attribute. +const base::Feature kDisablePolicyViolationExtensionsRemotely{ + "DisablePolicyViolationExtensionsRemotely", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether we show an install friction dialog when an Enhanced Safe // Browsing user tries to install an extension that is not included in the // Safe Browsing CRX allowlist. This feature also controls if we show a warning
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h index b2f8640..baa0c07 100644 --- a/extensions/common/extension_features.h +++ b/extensions/common/extension_features.h
@@ -10,6 +10,7 @@ namespace extensions_features { extern const base::Feature kDisableMalwareExtensionsRemotely; +extern const base::Feature kDisablePolicyViolationExtensionsRemotely; extern const base::Feature kSafeBrowsingCrxAllowlistShowWarnings; extern const base::Feature kSafeBrowsingCrxAllowlistAutoDisable;
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc index 1dc55b11..f31fe653 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.cc +++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -245,7 +245,7 @@ } std::unique_ptr<Event> event( - new Event(histogram_value, event_name, std::move(args))); + new Event(histogram_value, event_name, args->TakeList())); EventRouter::Get(browser_context_)->BroadcastEvent(std::move(event)); }
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn index aaf47ef..40b546d 100644 --- a/fuchsia/engine/BUILD.gn +++ b/fuchsia/engine/BUILD.gn
@@ -374,8 +374,8 @@ source_set("browsertest_core") { testonly = true sources = [ - "test/frame_test_helper.cc", - "test/frame_test_helper.h", + "test/frame_for_test.cc", + "test/frame_for_test.h", "test/test_data.cc", "test/test_data.h", "test/web_engine_browser_test.cc", @@ -446,6 +446,7 @@ "//testing/gtest", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.accessibility.semantics", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.input.virtualkeyboard", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mediacodec", "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp", "//ui/gfx", "//ui/ozone",
diff --git a/fuchsia/engine/browser/autoplay_browsertest.cc b/fuchsia/engine/browser/autoplay_browsertest.cc index fad72f7..0cacab9c 100644 --- a/fuchsia/engine/browser/autoplay_browsertest.cc +++ b/fuchsia/engine/browser/autoplay_browsertest.cc
@@ -14,6 +14,12 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom.h" +namespace { + +constexpr char kAutoplayVp8Url[] = "/play_vp8.html?autoplay=1&codecs=vp8"; + +} // namespace + class AutoplayTest : public cr_fuchsia::WebEngineBrowserTest { public: AutoplayTest() { @@ -53,7 +59,7 @@ IN_PROC_BROWSER_TEST_F( AutoplayTest, UserActivationPolicy_UserActivatedViaSimulatedInteraction) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html?autoplay=1")); + const GURL kUrl(embedded_test_server()->GetURL(kAutoplayVp8Url)); constexpr const char kPageLoadedTitle[] = "initial title"; fuchsia::web::FramePtr frame = @@ -76,7 +82,7 @@ IN_PROC_BROWSER_TEST_F(AutoplayTest, UserActivationPolicy_UserActivatedNavigation) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html?autoplay=1")); + const GURL kUrl(embedded_test_server()->GetURL(kAutoplayVp8Url)); fuchsia::web::FramePtr frame = CreateFrame(fuchsia::web::AutoplayPolicy::REQUIRE_USER_ACTIVATION); @@ -90,7 +96,7 @@ } IN_PROC_BROWSER_TEST_F(AutoplayTest, UserActivationPolicy_NoUserActivation) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html?autoplay=1")); + const GURL kUrl(embedded_test_server()->GetURL(kAutoplayVp8Url)); fuchsia::web::FramePtr frame = CreateFrame(fuchsia::web::AutoplayPolicy::REQUIRE_USER_ACTIVATION); @@ -105,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(AutoplayTest, AllowAllPolicy_DefaultNotUserActivatedNavigation) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html?autoplay=1")); + const GURL kUrl(embedded_test_server()->GetURL(kAutoplayVp8Url)); fuchsia::web::FramePtr frame = CreateFrame(fuchsia::web::AutoplayPolicy::ALLOW);
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc index 93cc405b..4c7bb15 100644 --- a/fuchsia/engine/browser/frame_impl_browsertest.cc +++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -80,7 +80,7 @@ const int64_t kOnLoadScriptId = 0; const char kChildQueryParamName[] = "child_url"; const char kPopupChildFile[] = "popup_child.html"; -const char kAutoplayFileAndQuery[] = "play_vp8.html?autoplay=1"; +const char kAutoplayFileAndQuery[] = "play_vp8.html?autoplay=1&codecs=vp8"; const char kAutoPlayBlockedTitle[] = "blocked"; const char kAutoPlaySuccessTitle[] = "playing";
diff --git a/fuchsia/engine/browser/media_browsertest.cc b/fuchsia/engine/browser/media_browsertest.cc index bfd3c21..84c12e4 100644 --- a/fuchsia/engine/browser/media_browsertest.cc +++ b/fuchsia/engine/browser/media_browsertest.cc
@@ -4,16 +4,30 @@ #include "fuchsia/engine/test/web_engine_browser_test.h" +#include <fuchsia/mediacodec/cpp/fidl_test_base.h> + #include "base/files/file_path.h" +#include "base/fuchsia/scoped_service_binding.h" +#include "base/fuchsia/test_component_context_for_process.h" #include "content/public/test/browser_test.h" #include "fuchsia/base/test/frame_test_util.h" #include "fuchsia/base/test/test_navigation_listener.h" #include "fuchsia/engine/switches.h" #include "fuchsia/engine/test/test_data.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace { +// Currently, VP8 can only be decoded in software, and VP9 can be decoded in +// hardware and software. The tests rely on this. +// TODO(crbug.com/1207695): Rename play_vp8.html to play_video.html. +constexpr char kLoadSoftwareOnlyCodecUrl[] = "/play_vp8.html?codecs=vp8"; +constexpr char kLoadHardwareAndSoftwareCodecUrl[] = "/play_vp8.html?codecs=vp9"; +constexpr char kCanPlaySoftwareOnlyCodecUrl[] = "/can_play_vp8.html"; + +} // namespace + class MediaTest : public cr_fuchsia::WebEngineBrowserTest { public: MediaTest() { @@ -21,42 +35,86 @@ } ~MediaTest() override = default; + MediaTest(const MediaTest&) = delete; + MediaTest& operator=(const MediaTest&) = delete; + + protected: void SetUpOnMainThread() override { CHECK(embedded_test_server()->Start()); cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread(); } - protected: // Creates a Frame with |navigation_listener_| attached. fuchsia::web::FramePtr CreateFrame() { return WebEngineBrowserTest::CreateFrame(&navigation_listener_); } cr_fuchsia::TestNavigationListener navigation_listener_; - - DISALLOW_COPY_AND_ASSIGN(MediaTest); }; -// VP8 can presently only be decoded in software. -// Verify that the --disable-software-video-decoders flag results in VP8 -// media being reported as unplayable. +using SoftwareDecoderEnabledTest = MediaTest; + +// MediaTest with switches::kDisableSoftwareVideoDecoders. class SoftwareDecoderDisabledTest : public MediaTest { public: SoftwareDecoderDisabledTest() = default; ~SoftwareDecoderDisabledTest() override = default; - void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kDisableSoftwareVideoDecoders); - cr_fuchsia::WebEngineBrowserTest::SetUp(); + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kDisableSoftwareVideoDecoders); + MediaTest::SetUpCommandLine(command_line); } - - private: - DISALLOW_COPY_AND_ASSIGN(SoftwareDecoderDisabledTest); }; -IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledTest, VP8IsTypeSupported) { - const GURL kUrl(embedded_test_server()->GetURL("/can_play_vp8.html")); +// SoftwareDecoderDisabledTest with fuchsia.mediacodec.CodecFactory +// disconnected. +class SoftwareDecoderDisabledAndHardwareDecoderFailureTest + : public SoftwareDecoderDisabledTest { + public: + SoftwareDecoderDisabledAndHardwareDecoderFailureTest() = default; + ~SoftwareDecoderDisabledAndHardwareDecoderFailureTest() override = default; + + protected: + // Removes the decoder service to cause calls to it to fail. + void SetUpOnMainThread() override { + component_context_.emplace( + base::TestComponentContextForProcess::InitialState::kCloneAll); + component_context_->additional_services() + ->RemovePublicService<fuchsia::mediacodec::CodecFactory>(); + + SoftwareDecoderDisabledTest::SetUpOnMainThread(); + } + + // Used to disconnect fuchsia.mediacodec.CodecFactory. + absl::optional<base::TestComponentContextForProcess> component_context_; +}; + +// Verify that a codec only supported by a software decoder is reported as +// playable if kDisableSoftwareVideoDecoders is not present. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderEnabledTest, + CanPlayTypeSoftwareOnlyCodecIsTrue) { + const GURL kUrl(embedded_test_server()->GetURL(kCanPlaySoftwareOnlyCodecUrl)); + + // TODO(crbug.com/1200314): Refactor these tests to use FrameForTest and + // possibly to simplify the calls below since some of the details are not + // interesting to the individual tests. In particular, has_user_activation is + // more relevant than speclific LoadUrlParams. + fuchsia::web::FramePtr frame = CreateFrame(); + + fuchsia::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec())); + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "can play vp8: true"); +} + +// Verify that a codec only supported by a software decoder is reported as not +// playable if kDisableSoftwareVideoDecoders is present. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledTest, + CanPlayTypeSoftwareOnlyCodecIsFalse) { + const GURL kUrl(embedded_test_server()->GetURL(kCanPlaySoftwareOnlyCodecUrl)); fuchsia::web::FramePtr frame = CreateFrame(); @@ -68,27 +126,11 @@ navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "can play vp8: false"); } -using SoftwareDecoderEnabledTest = MediaTest; - -// Verify that VP8 is reported as playable if --disable-software-video-decoders -// is unset. -IN_PROC_BROWSER_TEST_F(SoftwareDecoderEnabledTest, VP8IsTypeSupported) { - const GURL kUrl(embedded_test_server()->GetURL("/can_play_vp8.html")); - - fuchsia::web::FramePtr frame = CreateFrame(); - - fuchsia::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( - controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec())); - navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "can play vp8: true"); -} - -// Verify that a VP8 video is loaded if --disable-software-video-decoders is -// unset. -IN_PROC_BROWSER_TEST_F(SoftwareDecoderEnabledTest, PlayVP8) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html")); +// Verify that a codec only supported by a software decoder is loaded if +// kDisableSoftwareVideoDecoders is not present. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderEnabledTest, + PlaySoftwareOnlyCodecSucceeds) { + const GURL kUrl(embedded_test_server()->GetURL(kLoadSoftwareOnlyCodecUrl)); fuchsia::web::FramePtr frame = CreateFrame(); @@ -100,10 +142,11 @@ navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "loaded"); } -// Verifies that VP8 videos won't play if --disable-software-video-decoders is -// set. -IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledTest, PlayVP8Disabled) { - const GURL kUrl(embedded_test_server()->GetURL("/play_vp8.html")); +// Verify that a codec only supported by a software decoder is not loaded if +// kDisableSoftwareVideoDecoders is present. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledTest, + LoadSoftwareOnlyCodecFails) { + const GURL kUrl(embedded_test_server()->GetURL(kLoadSoftwareOnlyCodecUrl)); fuchsia::web::FramePtr frame = CreateFrame(); @@ -112,7 +155,55 @@ EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec())); - navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "error"); + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "media element error"); } -} // namespace +// Verify that a codec supported by hardware and software decoders plays if +// kDisableSoftwareVideoDecoders is present. +// Unlike the software-only codec, this codec loads and plays (when a hardware) +// decoder is actually available, such as on real hardware. +// TODO(crbug.com/1207695): Correct the final expected result to "playing". +// Currently, this fails in emulators. Fixing the bug will change this. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledTest, + PlayHardwareAndSoftwareCodecSucceeds) { + const GURL kUrl( + embedded_test_server()->GetURL(kLoadHardwareAndSoftwareCodecUrl)); + + fuchsia::web::FramePtr frame = CreateFrame(); + + fuchsia::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), cr_fuchsia::CreateLoadUrlParamsWithUserActivation(), + kUrl.spec())); + + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "loaded"); + cr_fuchsia::ExecuteJavaScript(frame.get(), "bear.play()"); + + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "media element error"); +} + +// Verify that a codec supported by hardware and software does not play if +// kDisableSoftwareVideoDecoders is present and the hardware decoder fails. +// Unlike the software-only codec, this codec loads because it is supposed to be +// supported but fails when the hardware decoder is unavailable. +IN_PROC_BROWSER_TEST_F(SoftwareDecoderDisabledAndHardwareDecoderFailureTest, + PlayHardwareAndSoftwareCodecFails) { + const GURL kUrl( + embedded_test_server()->GetURL(kLoadHardwareAndSoftwareCodecUrl)); + + fuchsia::web::FramePtr frame = CreateFrame(); + + fuchsia::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), cr_fuchsia::CreateLoadUrlParamsWithUserActivation(), + kUrl.spec())); + + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "loaded"); + cr_fuchsia::ExecuteJavaScript(frame.get(), "bear.play()"); + + navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "media element error"); +}
diff --git a/fuchsia/engine/browser/theme_manager_browsertest.cc b/fuchsia/engine/browser/theme_manager_browsertest.cc index ba69168..2a29413 100644 --- a/fuchsia/engine/browser/theme_manager_browsertest.cc +++ b/fuchsia/engine/browser/theme_manager_browsertest.cc
@@ -119,7 +119,9 @@ if (on_watch_closure_) std::move(on_watch_closure_).Run(); } - void NotImplemented_(const std::string&) final {} + void NotImplemented_(const std::string& name) final { + ADD_FAILURE() << "Unexpected call: " << name; + } absl::optional<base::TestComponentContextForProcess> component_context_; absl::optional<base::ScopedServiceBinding<fuchsia::settings::Display>>
diff --git a/fuchsia/engine/test/data/bear-vp9.webm b/fuchsia/engine/test/data/bear-vp9.webm new file mode 100644 index 0000000..4f497ae --- /dev/null +++ b/fuchsia/engine/test/data/bear-vp9.webm Binary files differ
diff --git a/fuchsia/engine/test/data/play_audio.html b/fuchsia/engine/test/data/play_audio.html index 8bfdddb..d8da238 100644 --- a/fuchsia/engine/test/data/play_audio.html +++ b/fuchsia/engine/test/data/play_audio.html
@@ -7,7 +7,7 @@ audio.src = URL.createObjectURL(mediaSource); audio.onended = function() { document.title = 'ended'; } - audio.onerror = function() { document.title = 'error'; } + audio.onerror = function() { document.title = 'media element error'; } // Play two files with different sample rate to force mid-stream // re-initialization.
diff --git a/fuchsia/engine/test/data/play_video.html b/fuchsia/engine/test/data/play_video.html deleted file mode 100644 index 35a347b..0000000 --- a/fuchsia/engine/test/data/play_video.html +++ /dev/null
@@ -1,25 +0,0 @@ -<html> - <head><title>initial title</title></head> - <body> - <script> - var bear = document.createElement('video'); - var isMetadataLoaded = false; - - var autoplay = (window.location.href.indexOf("autoplay") > 0); - if (autoplay) { - bear.autoplay = true; - } - - bear.onerror = function() { document.title = 'error'; } - bear.onloadeddata = function() { document.title = 'loaded'; } - bear.onloadedmetadata = function() { isMetadataLoaded = true; } - bear.onpause = function () { isPlaying = false; } - bear.onplay = function() { document.title = 'playing'; } - bear.onstalled = function() { document.title = 'stalled'; } - bear.onended = function() { document.title = 'ended'; } - bear.src = 'bear-vp9-opus.webm'; - - document.body.appendChild(bear); - </script> - </body> -</html>
diff --git a/fuchsia/engine/test/data/play_vp8.html b/fuchsia/engine/test/data/play_vp8.html index 6f0d088..c01ea8c 100644 --- a/fuchsia/engine/test/data/play_vp8.html +++ b/fuchsia/engine/test/data/play_vp8.html
@@ -2,20 +2,49 @@ <head><title>document loading</title></head> <body> <script> + // Returns the video file name corresponding to |codecs|. + // |codecs| may be null, in which case null will be returned. + // Otherwise, |codecs| is a comma-delimited string without spaces. + function getVideoFileNameForCodecs(codecs) { + if (!codecs) { + document.title = 'The "codecs" parameter is required.'; + return null; + } + + if (codecs == "vp8") { + return 'bear-vp8a.webm'; + } else if (codecs == "vp9,opus") { + return 'bear-vp9-opus.webm'; + } else if (codecs == "vp9") { + return 'bear-vp9.webm'; + } else { + document.title = 'Unrecognized value in "codecs" parameter'; + return null; + } + } var bear = document.createElement('video'); var isMetadataLoaded = false; var isPlaying = false; - var autoplay = (window.location.href.indexOf("autoplay") > 0); - if (autoplay) { + var params = new URLSearchParams(window.location.search); + var videoFile = getVideoFileNameForCodecs(params.get("codecs")); + + // Per https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video, + // "the video will autoplay if the attribute is there in the <video> tag + // at all." Therefore, only set the attribute if the parameter is true. + if (params.get("autoplay") == "1") { bear.autoplay = true; } - bear.onerror = function() { document.title = 'error'; } + // The title will only be changed from 'playing' to 'ended' if requested. + // This avoids potentially flaky tests if the video ends during the test. + var reportEnded = params.get("reportended") == "1"; + + bear.onerror = function() { document.title = 'media element error'; } bear.onloadeddata = function() { document.title = 'loaded'; - if (autoplay) { + if (bear.autoplay) { // No events are generated if autoplay's been denied, so use a // 0.2s timeout to detect and report the denial. window.setTimeout(function() { @@ -31,11 +60,20 @@ document.title = 'playing'; } bear.onstalled = function() { document.title = 'stalled'; } - bear.src = 'bear-vp8a.webm'; + bear.onended = function() { + if (reportEnded) { + document.title = 'ended'; + } + } - // Programatically set the title, to provide an externally-visible - // indication that the page's scripts have executed. - document.title = 'initial title'; + if (videoFile) { + // Programatically set the title, to provide an externally-visible + // indication that the page's scripts have executed. + document.title = 'initial title'; + + bear.src = videoFile; + } + // Else, the title should already be set to the error. </script> </body> </html>
diff --git a/fuchsia/engine/test/frame_for_test.cc b/fuchsia/engine/test/frame_for_test.cc new file mode 100644 index 0000000..191bc93 --- /dev/null +++ b/fuchsia/engine/test/frame_for_test.cc
@@ -0,0 +1,59 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "fuchsia/engine/test/frame_for_test.h" + +#include "fuchsia/base/test/test_navigation_listener.h" + +namespace cr_fuchsia { + +// static +FrameForTest FrameForTest::Create(fuchsia::web::Context* context, + fuchsia::web::CreateFrameParams params) { + FrameForTest result; + context->CreateFrameWithParams(std::move(params), result.frame_.NewRequest()); + result.CreateAndAttachNavigationListener(); + return result; +} + +// static +FrameForTest FrameForTest::Create(fuchsia::web::FrameHost* frame_host, + fuchsia::web::CreateFrameParams params) { + FrameForTest result; + frame_host->CreateFrameWithParams(std::move(params), + result.frame_.NewRequest()); + result.CreateAndAttachNavigationListener(); + return result; +} + +// static +FrameForTest FrameForTest::Create(const fuchsia::web::ContextPtr& context, + fuchsia::web::CreateFrameParams params) { + return Create(context.get(), std::move(params)); +} + +FrameForTest::FrameForTest() = default; + +FrameForTest::FrameForTest(FrameForTest&&) = default; + +FrameForTest& FrameForTest::operator=(FrameForTest&&) = default; + +FrameForTest::~FrameForTest() = default; + +fuchsia::web::NavigationControllerPtr FrameForTest::GetNavigationController() { + fuchsia::web::NavigationControllerPtr controller; + frame_->GetNavigationController(controller.NewRequest()); + return controller; +} + +void FrameForTest::CreateAndAttachNavigationListener() { + navigation_listener_ = std::make_unique<TestNavigationListener>(); + navigation_listener_binding_ = + std::make_unique<fidl::Binding<fuchsia::web::NavigationEventListener>>( + navigation_listener_.get()); + frame_->SetNavigationEventListener( + navigation_listener_binding_->NewBinding()); +} + +} // namespace cr_fuchsia
diff --git a/fuchsia/engine/test/frame_for_test.h b/fuchsia/engine/test/frame_for_test.h new file mode 100644 index 0000000..90ade83 --- /dev/null +++ b/fuchsia/engine/test/frame_for_test.h
@@ -0,0 +1,60 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FUCHSIA_ENGINE_TEST_FRAME_FOR_TEST_H_ +#define FUCHSIA_ENGINE_TEST_FRAME_FOR_TEST_H_ + +#include <fuchsia/web/cpp/fidl.h> +#include <lib/fidl/cpp/binding.h> +#include <memory> + +namespace cr_fuchsia { + +class TestNavigationListener; + +// Helper for tests which need to create fuchsia.web.Frames. +// Each instance owns a fuchsia.web.Frame, and attaches a TestNavigationListener +// to it. +class FrameForTest { + public: + // Returns a FrameForTest that encapsulates a new Frame, created using the + // specified container and |params|. + static FrameForTest Create(fuchsia::web::Context* context, + fuchsia::web::CreateFrameParams params); + static FrameForTest Create(fuchsia::web::FrameHost* frame_host, + fuchsia::web::CreateFrameParams params); + static FrameForTest Create(const fuchsia::web::ContextPtr& context, + fuchsia::web::CreateFrameParams params); + + FrameForTest(); + FrameForTest(FrameForTest&&); + FrameForTest& operator=(FrameForTest&&); + ~FrameForTest(); + + // Returns a new NavigationController for each call, which ensures that any + // calls made to |frame()| will have been processed before navigation + // controller requests. + fuchsia::web::NavigationControllerPtr GetNavigationController(); + + // Returns the fuchsia.web.FramePtr owned by this instance. + fuchsia::web::FramePtr& ptr() { return frame_; } + + // May be called only on non-default-initialized instances, i.e. those + // returned directly, or via move-assignment, from Create(). + TestNavigationListener& navigation_listener() { + return *navigation_listener_; + } + + private: + void CreateAndAttachNavigationListener(); + + fuchsia::web::FramePtr frame_; + std::unique_ptr<TestNavigationListener> navigation_listener_; + std::unique_ptr<fidl::Binding<fuchsia::web::NavigationEventListener>> + navigation_listener_binding_; +}; + +} // namespace cr_fuchsia + +#endif // FUCHSIA_ENGINE_TEST_FRAME_FOR_TEST_H_
diff --git a/fuchsia/engine/test/frame_test_helper.cc b/fuchsia/engine/test/frame_test_helper.cc deleted file mode 100644 index 294f5a8..0000000 --- a/fuchsia/engine/test/frame_test_helper.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "fuchsia/engine/test/frame_test_helper.h" - -namespace cr_fuchsia { - -FrameTestHelper::FrameTestHelper(fuchsia::web::Context* context, - fuchsia::web::CreateFrameParams params) - : navigation_listener_binding_(&navigation_listener_) { - context->CreateFrameWithParams(std::move(params), frame_.NewRequest()); - frame_->SetNavigationEventListener(navigation_listener_binding_.NewBinding()); -} - -FrameTestHelper::FrameTestHelper(fuchsia::web::FrameHost* frame_host, - fuchsia::web::CreateFrameParams params) - : navigation_listener_binding_(&navigation_listener_) { - frame_host->CreateFrameWithParams(std::move(params), frame_.NewRequest()); - frame_->SetNavigationEventListener(navigation_listener_binding_.NewBinding()); -} - -FrameTestHelper::FrameTestHelper(const fuchsia::web::ContextPtr& context, - fuchsia::web::CreateFrameParams params) - : FrameTestHelper(context.get(), std::move(params)) {} - -fuchsia::web::NavigationControllerPtr -FrameTestHelper::GetNavigationController() { - fuchsia::web::NavigationControllerPtr controller; - frame_->GetNavigationController(controller.NewRequest()); - return controller; -} - -} // namespace cr_fuchsia
diff --git a/fuchsia/engine/test/frame_test_helper.h b/fuchsia/engine/test/frame_test_helper.h deleted file mode 100644 index 5fba622..0000000 --- a/fuchsia/engine/test/frame_test_helper.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FUCHSIA_ENGINE_TEST_FRAME_TEST_HELPER_H_ -#define FUCHSIA_ENGINE_TEST_FRAME_TEST_HELPER_H_ - -#include <fuchsia/web/cpp/fidl.h> -#include <lib/fidl/cpp/binding.h> - -#include "fuchsia/base/test/test_navigation_listener.h" - -namespace cr_fuchsia { - -// Helper for tests which need to create fuchsia.web.Frames. -class FrameTestHelper { - public: - FrameTestHelper(fuchsia::web::Context* context, - fuchsia::web::CreateFrameParams params); - FrameTestHelper(fuchsia::web::FrameHost* frame_host, - fuchsia::web::CreateFrameParams params); - FrameTestHelper(const fuchsia::web::ContextPtr& context, - fuchsia::web::CreateFrameParams params); - ~FrameTestHelper(); - - FrameTestHelper(const FrameTestHelper&) = delete; - FrameTestHelper& operator=(const FrameTestHelper&) = delete; - - // Returns a new NavigationController for each call, which ensures that any - // calls made to |frame()| will have been processed before navigation - // controller requests. - fuchsia::web::NavigationControllerPtr GetNavigationController(); - - fuchsia::web::FramePtr& frame() { return frame_; } - TestNavigationListener& navigation_listener() { return navigation_listener_; } - - private: - fuchsia::web::FramePtr frame_; - TestNavigationListener navigation_listener_; - fidl::Binding<fuchsia::web::NavigationEventListener> - navigation_listener_binding_; -}; - -} // namespace cr_fuchsia - -#endif // FUCHSIA_ENGINE_TEST_FRAME_TEST_HELPER_H_
diff --git a/fuchsia/engine/web_engine_integration_test.cc b/fuchsia/engine/web_engine_integration_test.cc index 768d4118..942e445 100644 --- a/fuchsia/engine/web_engine_integration_test.cc +++ b/fuchsia/engine/web_engine_integration_test.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <fuchsia/mediacodec/cpp/fidl.h> #include <fuchsia/mem/cpp/fidl.h> #include <zircon/rights.h> #include <zircon/types.h> @@ -29,6 +30,15 @@ constexpr char kInvalidUserAgentProduct[] = "Test/Product"; constexpr char kInvalidUserAgentVersion[] = "dev/12345"; +// TODO(crbug.com/1207695): Rename play_vp8.html to play_video.html. +constexpr char kAutoplayVp9OpusUrl[] = + "fuchsia-dir://testdata/play_vp8.html?codecs=vp9,opus&autoplay=1"; +constexpr char kAutoplayVp9OpusToEndUrl[] = + "fuchsia-dir://testdata/" + "play_vp8.html?codecs=vp9,opus&autoplay=1&reportended=1"; +constexpr char kLoadVp9OpusUrl[] = + "fuchsia-dir://testdata/play_vp8.html?codecs=vp9,opus"; + } // namespace // Starts a WebEngine instance before running the test. @@ -317,7 +327,7 @@ "fuchsia-dir://testdata/play_audio.html", cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); - navigation_listener()->RunUntilTitleEquals("error"); + navigation_listener()->RunUntilTitleEquals("media element error"); EXPECT_FALSE(is_requested); } @@ -325,7 +335,7 @@ CreateContextAndFrame(ContextParamsWithAudioAndTestData()); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html?autoplay", + kAutoplayVp9OpusToEndUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); navigation_listener()->RunUntilTitleEquals("ended"); @@ -380,7 +390,7 @@ frame_->SetBlockMediaLoading(true); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html?autoplay", + kAutoplayVp9OpusUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); // Check different indicators that media has not loaded and is not playing. @@ -399,7 +409,7 @@ frame_->SetBlockMediaLoading(true); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html?autoplay", + kAutoplayVp9OpusUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); // Check that media loading has been blocked. @@ -419,8 +429,7 @@ CreateContextAndFrame(ContextParamsWithAudioAndTestData()); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html", - cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); + kLoadVp9OpusUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); navigation_listener()->RunUntilTitleEquals("loaded"); frame_->SetBlockMediaLoading(true); @@ -532,7 +541,7 @@ CreateContextAndFrame(std::move(create_params)); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html?autoplay", + kAutoplayVp9OpusToEndUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); navigation_listener()->RunUntilTitleEquals("ended"); @@ -555,7 +564,7 @@ CreateContextAndFrame(std::move(create_params)); ASSERT_NO_FATAL_FAILURE(LoadUrlAndExpectResponse( - "fuchsia-dir://testdata/play_video.html?autoplay", + kAutoplayVp9OpusToEndUrl, cr_fuchsia::CreateLoadUrlParamsWithUserActivation())); navigation_listener()->RunUntilTitleEquals("ended");
diff --git a/fuchsia/engine/web_engine_integration_test_base.h b/fuchsia/engine/web_engine_integration_test_base.h index af5c0ed..65ba780 100644 --- a/fuchsia/engine/web_engine_integration_test_base.h +++ b/fuchsia/engine/web_engine_integration_test_base.h
@@ -5,7 +5,6 @@ #ifndef FUCHSIA_ENGINE_WEB_ENGINE_INTEGRATION_TEST_BASE_H_ #define FUCHSIA_ENGINE_WEB_ENGINE_INTEGRATION_TEST_BASE_H_ -#include <fuchsia/mediacodec/cpp/fidl.h> #include <fuchsia/sys/cpp/fidl.h> #include <fuchsia/web/cpp/fidl.h> #include <lib/fidl/cpp/binding.h>
diff --git a/fuchsia/runners/BUILD.gn b/fuchsia/runners/BUILD.gn index f403160..1a78ec4 100644 --- a/fuchsia/runners/BUILD.gn +++ b/fuchsia/runners/BUILD.gn
@@ -78,6 +78,7 @@ ] deps = [ "//base", + "//components/cast/common:constants", "//components/cast/message_port", "//components/cast/named_message_port_connector:named_message_port_connector", "//fuchsia/base",
diff --git a/fuchsia/runners/cast/DEPS b/fuchsia/runners/cast/DEPS index 8129faaf..1a96cd7 100644 --- a/fuchsia/runners/cast/DEPS +++ b/fuchsia/runners/cast/DEPS
@@ -1,5 +1,4 @@ include_rules = [ - "+components/cast/message_port", - "+components/cast/named_message_port_connector", + "+components/cast", "+content/public/test", ]
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc index 522761e..420aa40b 100644 --- a/fuchsia/runners/cast/cast_runner.cc +++ b/fuchsia/runners/cast/cast_runner.cc
@@ -23,6 +23,7 @@ #include "base/strings/strcat.h" #include "base/time/time.h" #include "base/values.h" +#include "components/cast/common/constants.h" #include "fuchsia/base/agent_manager.h" #include "fuchsia/base/config_reader.h" #include "fuchsia/runners/cast/cast_streaming.h" @@ -562,9 +563,8 @@ EnsureSoftwareVideoDecodersAreDisabled(params.mutable_features()); params.set_remote_debugging_port(CastRunner::kRemoteDebuggingPort); - // TODO(crbug.com/1166790): Fetch UserAgent version strings from Agent. params.set_user_agent_product("CrKey"); - params.set_user_agent_version("1.52.999999"); + params.set_user_agent_version(chromecast::kFrozenCrKeyValue); zx_status_t status = main_services_->ConnectClient( params.mutable_service_directory()->NewRequest());
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc index b986d93e..0f56d6a 100644 --- a/gpu/config/gpu_util.cc +++ b/gpu/config/gpu_util.cc
@@ -44,6 +44,7 @@ #include "gpu/vulkan/buildflags.h" #include "ui/gfx/extension_set.h" #include "ui/gl/buildflags.h" +#include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" #if defined(OS_ANDROID) @@ -738,8 +739,10 @@ kGpuFeatureStatusEnabled || gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_GL] != kGpuFeatureStatusEnabled) { - command_line->AppendSwitchASCII( - switches::kUseGL, gl::kGLImplementationSwiftShaderForWebGLName); + // This setting makes WebGL run on legacy SwiftShader GL when true and + // SwANGLE when false. + bool legacy_software_gl = true; + gl::SetSoftwareWebGLCommandLineSwitches(command_line, legacy_software_gl); return true; } return false;
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc index 3c59c382..f15a5bd7 100644 --- a/headless/app/headless_shell.cc +++ b/headless/app/headless_shell.cc
@@ -785,6 +785,11 @@ command_line.GetSwitchValueASCII(switches::kUseGL)); } + if (command_line.HasSwitch(switches::kUseANGLE)) { + builder.SetANGLEImplementation( + command_line.GetSwitchValueASCII(switches::kUseANGLE)); + } + if (command_line.HasSwitch(switches::kUserDataDir)) { builder.SetUserDataDir( command_line.GetSwitchValuePath(switches::kUserDataDir));
diff --git a/headless/app/headless_shell_switches.cc b/headless/app/headless_shell_switches.cc index 5229318d..3ace56d 100644 --- a/headless/app/headless_shell_switches.cc +++ b/headless/app/headless_shell_switches.cc
@@ -105,6 +105,10 @@ // rendering. const char kUseGL[] = "use-gl"; +// Sets the ANGLE implementation to use. Only relevant if "use-gl" is set to +// "angle" +const char kUseANGLE[] = "use-angle"; + // A string used to override the default user agent with a custom one. const char kUserAgent[] = "user-agent";
diff --git a/headless/app/headless_shell_switches.h b/headless/app/headless_shell_switches.h index d10b842..00b3391 100644 --- a/headless/app/headless_shell_switches.h +++ b/headless/app/headless_shell_switches.h
@@ -33,6 +33,7 @@ HEADLESS_EXPORT extern const char kScreenshot[]; HEADLESS_EXPORT extern const char kSSLKeyLogFile[]; HEADLESS_EXPORT extern const char kTimeout[]; +HEADLESS_EXPORT extern const char kUseANGLE[]; HEADLESS_EXPORT extern const char kUseGL[]; HEADLESS_EXPORT extern const char kUserAgent[]; HEADLESS_EXPORT extern const char kUserDataDir[];
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc index 1a3ea19..c3ea2d3 100644 --- a/headless/lib/headless_content_main_delegate.cc +++ b/headless/lib/headless_content_main_delegate.cc
@@ -215,6 +215,10 @@ if (!options()->gl_implementation.empty()) { command_line->AppendSwitchASCII(::switches::kUseGL, options()->gl_implementation); + if (!options()->angle_implementation.empty()) { + command_line->AppendSwitchASCII(::switches::kUseANGLE, + options()->angle_implementation); + } } else { command_line->AppendSwitch(::switches::kDisableGpu); }
diff --git a/headless/public/headless_browser.cc b/headless/public/headless_browser.cc index e90e0c5..94da51c 100644 --- a/headless/public/headless_browser.cc +++ b/headless/public/headless_browser.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "build/build_config.h" #include "content/public/common/user_agent.h" #include "headless/public/version.h" #include "ui/gl/gl_switches.h" @@ -36,6 +37,7 @@ : argc(argc), argv(argv), gl_implementation(gl::kGLImplementationSwiftShaderForWebGLName), + angle_implementation(gl::kANGLEImplementationNoneName), product_name_and_version(GetProductNameAndVersion()), user_agent(content::BuildUserAgentFromProduct(product_name_and_version)), window_size(kDefaultWindowSize), @@ -119,6 +121,12 @@ return *this; } +Builder& Builder::SetANGLEImplementation( + const std::string& angle_implementation) { + options_.angle_implementation = angle_implementation; + return *this; +} + Builder& Builder::SetAppendCommandLineFlagsCallback( const Options::AppendCommandLineFlagsCallback& callback) { options_.append_command_line_flags_callback = callback;
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h index 9bcc978..80441a32 100644 --- a/headless/public/headless_browser.h +++ b/headless/public/headless_browser.h
@@ -150,6 +150,10 @@ // string can be used to disable GL rendering (e.g., WebGL support). std::string gl_implementation; + // Choose the ANGLE implementation to use for rendering. + // Only relevant if the gl_implementation above is set to "angle". + std::string angle_implementation; + // Default per-context options, can be specialized on per-context basis. std::string product_name_and_version; @@ -236,6 +240,7 @@ Builder& SetDisableSandbox(bool disable_sandbox); Builder& SetEnableResourceScheduler(bool enable_resource_scheduler); Builder& SetGLImplementation(const std::string& gl_implementation); + Builder& SetANGLEImplementation(const std::string& angle_implementation); Builder& SetAppendCommandLineFlagsCallback( const Options::AppendCommandLineFlagsCallback& callback); #if defined(OS_WIN)
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg index 2853a37e..f9dc579 100644 --- a/infra/config/generated/commit-queue.cfg +++ b/infra/config/generated/commit-queue.cfg
@@ -84,6 +84,12 @@ owner_whitelist_group: "project-chromium-robot-committers" } builders { + name: "chrome/try/lacros-arm-generic-chrome" + includable_only: true + owner_whitelist_group: "googlers" + owner_whitelist_group: "project-chromium-robot-committers" + } + builders { name: "chrome/try/linux-chrome" includable_only: true owner_whitelist_group: "googlers"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index 8b38102..95afc19 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -449,6 +449,11 @@ short_name: "lcr" } builders { + name: "buildbucket/luci.chrome.ci/lacros-arm-generic-chrome" + category: "chrome" + short_name: "lcr" + } + builders { name: "buildbucket/luci.chrome.ci/linux-chromeos-chrome" category: "chrome" short_name: "cro"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star index 584704b..abfc9b50 100644 --- a/infra/config/subprojects/chromium/ci.star +++ b/infra/config/subprojects/chromium/ci.star
@@ -435,6 +435,7 @@ short_name = short_name, ) for name, short_name in ( ("lacros-amd64-generic-chrome", "lcr"), + ("lacros-arm-generic-chrome", "lcr"), ("linux-chromeos-chrome", "cro"), ("linux-chrome", "lnx"), ("mac-chrome", "mac"),
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star index 7f369f4..d0838d64 100644 --- a/infra/config/subprojects/chromium/try.star +++ b/infra/config/subprojects/chromium/try.star
@@ -2155,6 +2155,10 @@ ) chrome_internal_verifier( + builder = "lacros-arm-generic-chrome", +) + +chrome_internal_verifier( builder = "linux-chrome", branch_selector = branches.STANDARD_MILESTONE, )
diff --git a/ios/build/tools/setup-gn.py b/ios/build/tools/setup-gn.py index 8c1697e0..4721c9e 100755 --- a/ios/build/tools/setup-gn.py +++ b/ios/build/tools/setup-gn.py
@@ -1,11 +1,13 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import argparse +import configparser import convert_gn_xcodeproj import errno +import io import os import re import shutil @@ -13,16 +15,6 @@ import sys import tempfile -try: - import configparser -except ImportError: - import ConfigParser as configparser - -try: - import StringIO as io -except ImportError: - import io - SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator', 'maccatalyst') SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage') @@ -41,7 +33,7 @@ re.compile('^settings append target.source-map .* /google/src/.*$'), ) -class ConfigParserWithStringInterpolation(configparser.SafeConfigParser): +class ConfigParserWithStringInterpolation(configparser.ConfigParser): '''A .ini file parser that supports strings and environment variables.''' @@ -55,7 +47,7 @@ def getstring(self, section, option, fallback=''): try: raw_value = self.get(section, option) - except configparser.NoOptionError, _: + except configparser.NoOptionError: return fallback return self._UnquoteString(self._ExpandEnvVar(raw_value))
diff --git a/ios/chrome/browser/context_menu/BUILD.gn b/ios/chrome/browser/context_menu/BUILD.gn index df554ea..c5a2f2e67 100644 --- a/ios/chrome/browser/context_menu/BUILD.gn +++ b/ios/chrome/browser/context_menu/BUILD.gn
@@ -15,6 +15,7 @@ "//base/test:test_support", "//components/strings", "//ios/chrome/app/strings", + "//ios/chrome/browser/ui/fullscreen:feature_flags", "//ios/chrome/browser/ui/fullscreen/test:eg_test_support+eg2", "//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/context_menu/context_menu_egtest.mm b/ios/chrome/browser/context_menu/context_menu_egtest.mm index f6b6620..3c919b7f 100644 --- a/ios/chrome/browser/context_menu/context_menu_egtest.mm +++ b/ios/chrome/browser/context_menu/context_menu_egtest.mm
@@ -10,6 +10,7 @@ #include "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" #include "components/strings/grit/components_strings.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h" #import "ios/chrome/browser/ui/fullscreen/test/fullscreen_app_interface.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" @@ -180,6 +181,14 @@ @implementation ContextMenuTestCase +- (AppLaunchConfiguration)appConfigurationForTestCase { + AppLaunchConfiguration config; + + config.features_disabled.push_back( + fullscreen::features::kSmoothScrollingDefault); + return config; +} + + (void)setUpForTestCase { [super setUpForTestCase]; [ChromeEarlGrey setContentSettings:CONTENT_SETTING_ALLOW]; @@ -265,8 +274,7 @@ // Calculate a point inside the displayed image. CGFloat topInset = 0.0; - if ([ChromeEarlGrey webStateWebViewUsesContentInset] || - [FullscreenAppInterface isFullscreenInitialized]) { + if ([ChromeEarlGrey webStateWebViewUsesContentInset]) { topInset = [FullscreenAppInterface currentViewportInsets].top; } CGPoint pointOnImage = CGPointZero;
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h index 480f4c58..f1b51e37 100644 --- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h +++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h
@@ -7,7 +7,7 @@ #include <string> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ios/chrome/browser/main/browser_observer.h" #include "ios/chrome/browser/main/browser_user_data.h" #include "ios/chrome/browser/overlays/public/overlay_presenter.h" @@ -136,7 +136,8 @@ std::unique_ptr<BatchOperation> batch_operation_; // Observes overlays presentation. - ScopedObserver<OverlayPresenter, OverlayPresenterObserver> overlay_observer_; + base::ScopedObservation<OverlayPresenter, OverlayPresenterObserver> + overlay_observation_{this}; }; #endif // IOS_CHROME_BROWSER_CRASH_REPORT_BREADCRUMBS_BREADCRUMB_MANAGER_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.mm b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.mm index 1e1b3b6..771a8d8 100644 --- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.mm +++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.mm
@@ -37,14 +37,14 @@ BROWSER_USER_DATA_KEY_IMPL(BreadcrumbManagerBrowserAgent) BreadcrumbManagerBrowserAgent::BreadcrumbManagerBrowserAgent(Browser* browser) - : browser_(browser), overlay_observer_(this) { + : browser_(browser) { static int next_unique_id = 1; unique_id_ = next_unique_id++; browser_->AddObserver(this); browser_->GetWebStateList()->AddObserver(this); - overlay_observer_.Add( + overlay_observation_.Observe( OverlayPresenter::FromBrowser(browser, OverlayModality::kWebContentArea)); } @@ -208,5 +208,6 @@ void BreadcrumbManagerBrowserAgent::OverlayPresenterDestroyed( OverlayPresenter* presenter) { - overlay_observer_.Remove(presenter); + DCHECK(overlay_observation_.IsObservingSource(presenter)); + overlay_observation_.Reset(); }
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.h b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.h index 506931d..4ae8587 100644 --- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.h +++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.h
@@ -7,7 +7,7 @@ #include <string> -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/infobars/core/infobar_manager.h" #include "ios/web/public/web_state_observer.h" #import "ios/web/public/web_state_user_data.h" @@ -154,8 +154,9 @@ int sequentially_scrolled_ = 0; // Manages this object as an observer of infobars. - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - infobar_observer_; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + infobar_observation_{this}; // Allows observing Objective-C object for Scroll and Zoom events. __strong id<CRWWebViewScrollViewProxyObserver> scroll_observer_;
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.mm b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.mm index 22efc7c1..7d8bd36 100644 --- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.mm +++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_tab_helper.mm
@@ -106,14 +106,13 @@ BreadcrumbManagerTabHelper::BreadcrumbManagerTabHelper(web::WebState* web_state) : web_state_(web_state), - infobar_manager_(InfoBarManagerImpl::FromWebState(web_state)), - infobar_observer_(this) { + infobar_manager_(InfoBarManagerImpl::FromWebState(web_state)) { web_state_->AddObserver(this); static int next_unique_id = 1; unique_id_ = next_unique_id++; - infobar_observer_.Add(infobar_manager_); + infobar_observation_.Observe(infobar_manager_); scroll_observer_ = [[BreadcrumbScrollingObserver alloc] initWithLoggingBlock:^(const std::string& event) { @@ -307,7 +306,8 @@ void BreadcrumbManagerTabHelper::OnManagerShuttingDown( infobars::InfoBarManager* manager) { DCHECK_EQ(infobar_manager_, manager); - infobar_observer_.Remove(manager); + DCHECK(infobar_observation_.IsObservingSource(manager)); + infobar_observation_.Reset(); infobar_manager_ = nullptr; sequentially_replaced_infobars_ = 0; }
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h index f91aeba..e287273d 100644 --- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h +++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
@@ -7,7 +7,8 @@ #include <map> -#include "base/scoped_observer.h" +#include "base/scoped_multi_source_observation.h" +#include "base/scoped_observation.h" #include "components/infobars/core/infobar_manager.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/infobars/infobar_type.h" @@ -64,9 +65,10 @@ explicit InfobarAcceptanceObserver(InfobarBadgeTabHelper* tab_helper); ~InfobarAcceptanceObserver() override; - // Returns a reference to the scoped observer. - ScopedObserver<InfoBarIOS, InfoBarIOS::Observer>& scoped_observer() { - return scoped_observer_; + // Returns a reference to the scoped observations. + base::ScopedMultiSourceObservation<InfoBarIOS, InfoBarIOS::Observer>& + scoped_observations() { + return scoped_observations_; } private: @@ -77,7 +79,8 @@ // The owning tab helper. InfobarBadgeTabHelper* tab_helper_ = nullptr; // Scoped observer that facilitates observing InfoBarIOS objects. - ScopedObserver<InfoBarIOS, InfoBarIOS::Observer> scoped_observer_; + base::ScopedMultiSourceObservation<InfoBarIOS, InfoBarIOS::Observer> + scoped_observations_{this}; }; // Helper object that updates state and adds an InfobarAcceptanceObserver @@ -103,8 +106,9 @@ // in the observed manager. InfobarAcceptanceObserver* infobar_accept_observer_ = nullptr; // Scoped observer that facilitates observing an InfoBarManager. - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - scoped_observer_; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + scoped_observation_{this}; }; // Delegate which displays the Infobar badge.
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm index 97df4f00..02023b5 100644 --- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm +++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
@@ -112,7 +112,7 @@ InfobarBadgeTabHelper::InfobarAcceptanceObserver::InfobarAcceptanceObserver( InfobarBadgeTabHelper* tab_helper) - : tab_helper_(tab_helper), scoped_observer_(this) { + : tab_helper_(tab_helper) { DCHECK(tab_helper_); } @@ -127,7 +127,7 @@ void InfobarBadgeTabHelper::InfobarAcceptanceObserver::InfobarDestroyed( InfoBarIOS* infobar) { - scoped_observer_.Remove(infobar); + scoped_observations_.RemoveObservation(infobar); } #pragma mark - InfobarBadgeTabHelper::InfobarManagerObserver @@ -137,11 +137,10 @@ web::WebState* web_state, InfobarAcceptanceObserver* infobar_accept_observer) : tab_helper_(tab_helper), - infobar_accept_observer_(infobar_accept_observer), - scoped_observer_(this) { + infobar_accept_observer_(infobar_accept_observer) { DCHECK(tab_helper_); DCHECK(infobar_accept_observer_); - scoped_observer_.Add(InfoBarManagerImpl::FromWebState(web_state)); + scoped_observation_.Observe(InfoBarManagerImpl::FromWebState(web_state)); } InfobarBadgeTabHelper::InfobarManagerObserver::~InfobarManagerObserver() = @@ -151,7 +150,7 @@ infobars::InfoBar* infobar) { if (SupportsBadges(infobar)) { tab_helper_->ResetStateForAddedInfobar(GetInfobarType(infobar)); - infobar_accept_observer_->scoped_observer().Add( + infobar_accept_observer_->scoped_observations().AddObservation( static_cast<InfoBarIOS*>(infobar)); } } @@ -161,7 +160,7 @@ bool animate) { if (SupportsBadges(infobar)) { tab_helper_->ResetStateForRemovedInfobar(GetInfobarType(infobar)); - infobar_accept_observer_->scoped_observer().Remove( + infobar_accept_observer_->scoped_observations().RemoveObservation( static_cast<InfoBarIOS*>(infobar)); } } @@ -175,5 +174,6 @@ void InfobarBadgeTabHelper::InfobarManagerObserver::OnManagerShuttingDown( infobars::InfoBarManager* manager) { - scoped_observer_.Remove(manager); + DCHECK(scoped_observation_.IsObservingSource(manager)); + scoped_observation_.Reset(); }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h index 031bead..aea240f 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.h
@@ -8,7 +8,7 @@ #include <map> #include <memory> -#include "base/scoped_observer.h" +#include "base/scoped_multi_source_observation.h" #import "ios/chrome/browser/infobars/infobar_type.h" #import "ios/chrome/browser/main/browser_user_data.h" #import "ios/chrome/browser/overlays/public/overlay_browser_agent_base.h" @@ -65,7 +65,9 @@ void OverlayPresenterDestroyed(OverlayPresenter* presenter) override; InfobarOverlayBrowserAgent* browser_agent_ = nullptr; - ScopedObserver<OverlayPresenter, OverlayPresenterObserver> scoped_observer_; + base::ScopedMultiSourceObservation<OverlayPresenter, + OverlayPresenterObserver> + scoped_observations_{this}; }; // The interaction handlers for each InfobarType.
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.mm b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.mm index 1aa6038d..f3922f4 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent.mm
@@ -58,11 +58,11 @@ InfobarOverlayBrowserAgent::OverlayVisibilityObserver:: OverlayVisibilityObserver(Browser* browser, InfobarOverlayBrowserAgent* browser_agent) - : browser_agent_(browser_agent), scoped_observer_(this) { + : browser_agent_(browser_agent) { DCHECK(browser_agent_); - scoped_observer_.Add( + scoped_observations_.AddObservation( OverlayPresenter::FromBrowser(browser, OverlayModality::kInfobarBanner)); - scoped_observer_.Add( + scoped_observations_.AddObservation( OverlayPresenter::FromBrowser(browser, OverlayModality::kInfobarModal)); } @@ -98,5 +98,5 @@ void InfobarOverlayBrowserAgent::OverlayVisibilityObserver:: OverlayPresenterDestroyed(OverlayPresenter* presenter) { - scoped_observer_.Remove(presenter); + scoped_observations_.RemoveObservation(presenter); }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn index 8528d5d..97721d3 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn
@@ -27,6 +27,7 @@ "//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays/public/infobar_banner", "//ios/chrome/browser/overlays/public/infobar_modal", + "//ios/chrome/browser/ui/autofill:autofill_ui_type", "//ios/chrome/browser/web_state_list", ] } @@ -37,6 +38,7 @@ sources = [ "save_address_profile_infobar_banner_interaction_handler_unittest.mm", "save_address_profile_infobar_modal_interaction_handler_unittest.mm", + "save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm", ] deps = [ ":autofill_address_profile",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h index 3eab1bf..ef7b88c5 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
@@ -25,10 +25,9 @@ void PerformMainAction(InfoBarIOS* infobar) override; void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override; - // Instructs the handler that the user has requested the address profile - // settings page through |infobar|'s modal UI. The settings will be presented - // after the dismissal of |infobar|'s modal UI. - void PresentAddressProfileSettings(InfoBarIOS* infobar); + // Instructs the handler that the user has edited and then saved the profile. + virtual void SaveEditedProfile(InfoBarIOS* infobar, + NSDictionary* profileData); private: // InfobarModalInteractionHandler:
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm index f0e6b4ff..13d7294 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm
@@ -4,9 +4,12 @@ #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h" +#include "base/strings/sys_string_conversions.h" #include "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h" +#include "components/autofill/core/browser/field_types.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h" +#import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -23,6 +26,9 @@ void SaveAddressProfileInfobarModalInteractionHandler::PerformMainAction( InfoBarIOS* infobar) { infobar->set_accepted(GetInfoBarDelegate(infobar)->Accept()); + // Post save, the infobar should not be brought back from the omnibox + // icon. + infobar->RemoveSelf(); } void SaveAddressProfileInfobarModalInteractionHandler::InfobarVisibilityChanged( @@ -35,9 +41,19 @@ } } -void SaveAddressProfileInfobarModalInteractionHandler:: - PresentAddressProfileSettings(InfoBarIOS* infobar) { - // TODO(crbug.com/1167062): Open Address Profile settings. +void SaveAddressProfileInfobarModalInteractionHandler::SaveEditedProfile( + InfoBarIOS* infobar, + NSDictionary* profileData) { + for (NSNumber* key in profileData) { + autofill::ServerFieldType type = + AutofillTypeFromAutofillUIType((AutofillUIType)[key intValue]); + std::u16string data = base::SysNSStringToUTF16(profileData[key]); + GetInfoBarDelegate(infobar)->SetProfileRawInfo(type, data); + } + infobar->set_accepted(GetInfoBarDelegate(infobar)->EditAccepted()); + // On post-edit save, the infobar should not be brought back from the omnibox + // icon. + infobar->RemoveSelf(); } #pragma mark - Private
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm index d2c83db..b8e11aa 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm
@@ -50,3 +50,9 @@ EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true)); handler_.PerformMainAction(infobar_.get()); } + +TEST_F(SaveAddressProfileInfobarModalInteractionHandlerTest, + SaveEditedProfile) { + EXPECT_CALL(mock_delegate(), EditAccepted()).WillOnce(testing::Return(true)); + handler_.SaveEditedProfile(infobar_.get(), @{}.mutableCopy); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h index 05493cde..34abf92 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h
@@ -25,9 +25,9 @@ // Used as a callback for OverlayResponses dispatched through |request|'s // callback manager. The OverlayDispatchCallback is created with an // OverlayResponseSupport that guarantees that |response| is created with a - // save_address_profile_infobar_modal_responses::PresentAddressProfileSettings. - void PresentAddressProfileSettingsCallback(OverlayRequest* request, - OverlayResponse* response); + // save_address_profile_infobar_modal_responses::EditedProfileSaveAction. + void SaveEditedProfileDetailsCallback(OverlayRequest* request, + OverlayResponse* response); // OverlayRequestCallbackInstaller: void InstallCallbacksInternal(OverlayRequest* request) override;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm index 7a48344..b381969 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm
@@ -21,8 +21,7 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; -using save_address_profile_infobar_modal_responses:: - PresentAddressProfileSettings; +using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller( @@ -37,15 +36,19 @@ SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: ~SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller() = default; +#pragma mark - Private + void SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: - PresentAddressProfileSettingsCallback(OverlayRequest* request, - OverlayResponse* response) { + SaveEditedProfileDetailsCallback(OverlayRequest* request, + OverlayResponse* response) { InfoBarIOS* infobar = GetOverlayRequestInfobar(request); if (!infobar) { return; } - interaction_handler_->PresentAddressProfileSettings(infobar); + EditedProfileSaveAction* info = response->GetInfo<EditedProfileSaveAction>(); + interaction_handler_->SaveEditedProfile(GetOverlayRequestInfobar(request), + info->profile_data()); } #pragma mark - OverlayRequestCallbackInstaller @@ -59,7 +62,7 @@ manager->AddDispatchCallback(OverlayDispatchCallback( base::BindRepeating( &SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: - PresentAddressProfileSettingsCallback, + SaveEditedProfileDetailsCallback, weak_factory_.GetWeakPtr(), request), - PresentAddressProfileSettings::ResponseSupport())); + EditedProfileSaveAction::ResponseSupport())); }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm new file mode 100644 index 0000000..9cc2364 --- /dev/null +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm
@@ -0,0 +1,94 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h" + +#include "base/guid.h" +#include "base/strings/sys_string_conversions.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/data_model/autofill_profile.h" +#include "ios/chrome/browser/infobars/infobar_ios.h" +#include "ios/chrome/browser/infobars/infobar_manager_impl.h" +#include "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h" +#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/infobar_modal_overlay_responses.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h" +#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#include "ios/chrome/browser/overlays/public/overlay_request_queue.h" +#include "ios/chrome/browser/overlays/public/overlay_response.h" +#import "ios/web/public/test/fakes/fake_navigation_manager.h" +#import "ios/web/public/test/fakes/fake_web_state.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using autofill_address_profile_infobar_overlays:: + SaveAddressProfileModalRequestConfig; +using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; + +// Test fixture for +// SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller. +class SaveAddressProfileInfobarModalOverlayRequestCallbackInstallerTest + : public PlatformTest { + public: + SaveAddressProfileInfobarModalOverlayRequestCallbackInstallerTest() + : profile_(base::GenerateGUID(), "https://www.example.com/"), + installer_(&mock_handler_), + delegate_factory_() { + // Create the infobar and add it to the WebState's manager. + web_state_.SetNavigationManager( + std::make_unique<web::FakeNavigationManager>()); + InfoBarManagerImpl::CreateForWebState(&web_state_); + std::unique_ptr<MockAutofillSaveUpdateAddressProfileDelegateIOS> delegate = + delegate_factory_ + .CreateMockAutofillSaveUpdateAddressProfileDelegateIOSFactory( + profile_); + delegate_ = delegate.get(); + std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>( + InfobarType::kInfobarTypeSaveAutofillAddressProfile, + std::move(delegate)); + + infobar_ = infobar.get(); + manager()->AddInfoBar(std::move(infobar)); + // Create the request and add it to the WebState's queue. + std::unique_ptr<OverlayRequest> added_request = + OverlayRequest::CreateWithConfig<SaveAddressProfileModalRequestConfig>( + infobar_); + request_ = added_request.get(); + queue()->AddRequest(std::move(added_request)); + // Install the callbacks on the added request. + installer_.InstallCallbacks(request_); + } + + InfoBarManagerImpl* manager() { + return InfoBarManagerImpl::FromWebState(&web_state_); + } + OverlayRequestQueue* queue() { + return OverlayRequestQueue::FromWebState(&web_state_, + OverlayModality::kInfobarModal); + } + + protected: + autofill::AutofillProfile profile_; + web::FakeWebState web_state_; + InfoBarIOS* infobar_ = nullptr; + OverlayRequest* request_ = nullptr; + MockSaveAddressProfileInfobarModalInteractionHandler mock_handler_; + SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller installer_; + MockAutofillSaveUpdateAddressProfileDelegateIOSFactory delegate_factory_; + MockAutofillSaveUpdateAddressProfileDelegateIOS* delegate_; +}; + +TEST_F(SaveAddressProfileInfobarModalOverlayRequestCallbackInstallerTest, + SaveEditedProfile) { + NSDictionary* empty = @{}.mutableCopy; + EXPECT_CALL(mock_handler_, SaveEditedProfile(infobar_, empty)); + request_->GetCallbackManager()->DispatchResponse( + OverlayResponse::CreateWithInfo<EditedProfileSaveAction>(empty)); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn index c7ba1abb0..4b3d3dd 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/BUILD.gn
@@ -11,6 +11,8 @@ "mock_autofill_save_update_address_profile_delegate_ios.mm", "mock_infobar_interaction_handler.h", "mock_infobar_interaction_handler.mm", + "mock_save_address_profile_modal_infobar_interaction_handler.h", + "mock_save_address_profile_modal_infobar_interaction_handler.mm", "mock_save_card_banner_infobar_interaction_handler.h", "mock_save_card_banner_infobar_interaction_handler.mm", "mock_save_card_modal_infobar_interaction_handler.h", @@ -29,8 +31,10 @@ "//ios/chrome/browser/infobars:public", "//ios/chrome/browser/infobars/overlays", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers", + "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/save_card", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/translate", + "//ios/chrome/browser/main:test_support", "//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays/public/common/infobars", "//ios/chrome/browser/overlays/public/infobar_banner",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h index aa8663a..b7a2fd6 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h
@@ -26,6 +26,7 @@ MOCK_METHOD0(Accept, bool()); MOCK_METHOD0(InfoBarDismissed, void()); + MOCK_METHOD0(EditAccepted, bool()); }; class MockAutofillSaveUpdateAddressProfileDelegateIOSFactory {
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h new file mode 100644 index 0000000..696c1a9 --- /dev/null +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_SAVE_ADDRESS_PROFILE_MODAL_INFOBAR_INTERACTION_HANDLER_H_ +#define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_SAVE_ADDRESS_PROFILE_MODAL_INFOBAR_INTERACTION_HANDLER_H_ + +#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h" + +#include "testing/gmock/include/gmock/gmock.h" + +class InfoBarIOS; + +// Mock version of SaveAddressProfileInfobarModalInteractionHandler for use in +// tests. +class MockSaveAddressProfileInfobarModalInteractionHandler + : public SaveAddressProfileInfobarModalInteractionHandler { + public: + MockSaveAddressProfileInfobarModalInteractionHandler(); + ~MockSaveAddressProfileInfobarModalInteractionHandler(); + + MOCK_METHOD2(SaveEditedProfile, + void(InfoBarIOS* infobar, NSDictionary* profileData)); +}; + +#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_SAVE_ADDRESS_PROFILE_MODAL_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.mm new file mode 100644 index 0000000..610673d --- /dev/null +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.mm
@@ -0,0 +1,15 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +MockSaveAddressProfileInfobarModalInteractionHandler:: + MockSaveAddressProfileInfobarModalInteractionHandler() = default; + +MockSaveAddressProfileInfobarModalInteractionHandler:: + ~MockSaveAddressProfileInfobarModalInteractionHandler() = default;
diff --git a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h index 49a5520..000c37c 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.h
@@ -7,7 +7,7 @@ #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h" #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h" @@ -44,9 +44,9 @@ InfobarBannerOverlayRequestCancelHandler* cancel_handler_ = nullptr; // The infobar for which to look for modal insertions. InfoBarIOS* infobar_ = nullptr; - ScopedObserver<InfobarOverlayRequestInserter, - InfobarOverlayRequestInserter::Observer> - scoped_observer_; + base::ScopedObservation<InfobarOverlayRequestInserter, + InfobarOverlayRequestInserter::Observer> + scoped_observation_{this}; }; // Helper object that triggers request cancellation for the completion of @@ -71,9 +71,9 @@ InfobarBannerOverlayRequestCancelHandler* cancel_handler_ = nullptr; // The infobar whose modal dismissals should trigger cancellation. InfoBarIOS* infobar_ = nullptr; - ScopedObserver<InfobarModalCompletionNotifier, - InfobarModalCompletionNotifier::Observer> - scoped_observer_; + base::ScopedObservation<InfobarModalCompletionNotifier, + InfobarModalCompletionNotifier::Observer> + scoped_observation_{this}; }; // Indicates to the cancel handler that its banner presented a modal.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.mm b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.mm index 8769e47..e27e6c3 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_banner_overlay_request_cancel_handler.mm
@@ -67,13 +67,11 @@ InfobarOverlayRequestInserter* inserter, InfoBarIOS* infobar, InfobarBannerOverlayRequestCancelHandler* cancel_handler) - : cancel_handler_(cancel_handler), - infobar_(infobar), - scoped_observer_(this) { + : cancel_handler_(cancel_handler), infobar_(infobar) { DCHECK(inserter); DCHECK(infobar); DCHECK(cancel_handler); - scoped_observer_.Add(inserter); + scoped_observation_.Observe(inserter); } InfobarBannerOverlayRequestCancelHandler::InsertionObserver:: @@ -89,7 +87,8 @@ void InfobarBannerOverlayRequestCancelHandler::InsertionObserver:: InserterDestroyed(InfobarOverlayRequestInserter* inserter) { - scoped_observer_.Remove(inserter); + DCHECK(scoped_observation_.IsObservingSource(inserter)); + scoped_observation_.Reset(); } #pragma mark - InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver @@ -99,13 +98,11 @@ InfobarBannerOverlayRequestCancelHandler* cancel_handler, InfobarModalCompletionNotifier* completion_notifier, InfoBarIOS* infobar) - : cancel_handler_(cancel_handler), - infobar_(infobar), - scoped_observer_(this) { + : cancel_handler_(cancel_handler), infobar_(infobar) { DCHECK(cancel_handler_); DCHECK(infobar_); DCHECK(completion_notifier); - scoped_observer_.Add(completion_notifier); + scoped_observation_.Observe(completion_notifier); } InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver:: @@ -124,7 +121,8 @@ void InfobarBannerOverlayRequestCancelHandler::ModalCompletionObserver:: InfobarModalCompletionNotifierDestroyed( InfobarModalCompletionNotifier* notifier) { - scoped_observer_.Remove(notifier); + DCHECK(scoped_observation_.IsObservingSource(notifier)); + scoped_observation_.Reset(); cancel_handler_->ModalCompleted(); // The cancel handler is destroyed after CancelForModalCompletion(), so no // code can be added after this call.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm index 51048eb4..5ed47ea1 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier_unittest.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/infobars/test/fake_infobar_ios.h" #import "ios/chrome/browser/overlays/public/common/infobars/infobar_overlay_request_config.h" #include "ios/chrome/browser/overlays/public/overlay_request_queue.h" @@ -34,9 +34,8 @@ // Test fixture for InfobarModalCompletionNotifier. class InfobarModalCompletionNotifierTest : public PlatformTest { public: - InfobarModalCompletionNotifierTest() - : notifier_(&web_state_), scoped_observer_(&observer_) { - scoped_observer_.Add(¬ifier_); + InfobarModalCompletionNotifierTest() : notifier_(&web_state_) { + scoped_observation_.Observe(¬ifier_); } OverlayRequestQueue* queue() { @@ -49,9 +48,9 @@ FakeInfobarIOS infobar_; InfobarModalCompletionNotifier notifier_; MockInfobarModalCompletionNotifierObserver observer_; - ScopedObserver<InfobarModalCompletionNotifier, - InfobarModalCompletionNotifier::Observer> - scoped_observer_; + base::ScopedObservation<InfobarModalCompletionNotifier, + InfobarModalCompletionNotifier::Observer> + scoped_observation_{&observer_}; }; // Tests that the observer is notified when all modal requests for |infobar_|
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h index 3609aa2..49a514f2 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.h
@@ -7,7 +7,7 @@ #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/infobars/overlays/infobar_modal_completion_notifier.h" // A cancel handler for Infobar modal UI OverlayRequests. @@ -46,9 +46,9 @@ InfobarModalOverlayRequestCancelHandler* cancel_handler_ = nullptr; // The infobar whose modal dismissals should trigger cancellation. InfoBarIOS* infobar_ = nullptr; - ScopedObserver<InfobarModalCompletionNotifier, - InfobarModalCompletionNotifier::Observer> - scoped_observer_; + base::ScopedObservation<InfobarModalCompletionNotifier, + InfobarModalCompletionNotifier::Observer> + scoped_observation_{this}; }; // Cancels the request for modal completion.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.mm b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.mm index 45bec16..3606f99c 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_modal_overlay_request_cancel_handler.mm
@@ -35,13 +35,11 @@ InfobarModalOverlayRequestCancelHandler* cancel_handler, InfobarModalCompletionNotifier* completion_notifier, InfoBarIOS* infobar) - : cancel_handler_(cancel_handler), - infobar_(infobar), - scoped_observer_(this) { + : cancel_handler_(cancel_handler), infobar_(infobar) { DCHECK(cancel_handler_); DCHECK(infobar_); DCHECK(completion_notifier); - scoped_observer_.Add(completion_notifier); + scoped_observation_.Observe(completion_notifier); } InfobarModalOverlayRequestCancelHandler::ModalCompletionObserver:: @@ -60,7 +58,8 @@ void InfobarModalOverlayRequestCancelHandler::ModalCompletionObserver:: InfobarModalCompletionNotifierDestroyed( InfobarModalCompletionNotifier* notifier) { - scoped_observer_.Remove(notifier); + DCHECK(scoped_observation_.IsObservingSource(notifier)); + scoped_observation_.Reset(); cancel_handler_->CancelForModalCompletion(); // The cancel handler is destroyed after CancelForModalCompletion(), so no // code can be added after this call.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h index 0ad415f..2628532 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_INFOBAR_OVERLAY_REQUEST_CANCEL_HANDLER_H_ #define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_INFOBAR_OVERLAY_REQUEST_CANCEL_HANDLER_H_ -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/infobars/core/infobar_manager.h" #import "ios/chrome/browser/overlays/public/overlay_request_cancel_handler.h" @@ -48,8 +48,9 @@ private: InfobarOverlayRequestCancelHandler* cancel_handler_ = nullptr; - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - scoped_observer_; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + scoped_observation_{this}; }; InfoBarIOS* infobar_ = nullptr;
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm index 03e047d..28b0a41b 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.mm
@@ -48,11 +48,11 @@ InfobarOverlayRequestCancelHandler::RemovalObserver::RemovalObserver( InfobarOverlayRequestCancelHandler* cancel_handler) - : cancel_handler_(cancel_handler), scoped_observer_(this) { + : cancel_handler_(cancel_handler) { DCHECK(cancel_handler_); InfoBarManager* manager = cancel_handler_->infobar()->owner(); DCHECK(manager); - scoped_observer_.Add(manager); + scoped_observation_.Observe(manager); } InfobarOverlayRequestCancelHandler::RemovalObserver::~RemovalObserver() = @@ -81,7 +81,8 @@ void InfobarOverlayRequestCancelHandler::RemovalObserver::OnManagerShuttingDown( infobars::InfoBarManager* manager) { - scoped_observer_.Remove(manager); + DCHECK(scoped_observation_.IsObservingSource(manager)); + scoped_observation_.Reset(); cancel_handler_->CancelForInfobarRemoval(); // The cancel handler is destroyed after Cancel(), so no code can be added // after this call.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.h b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.h index 122d6ef4..a2dfa3e 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.h +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.h
@@ -5,8 +5,7 @@ #ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_INFOBAR_OVERLAY_TAB_HELPER_H_ #define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_INFOBAR_OVERLAY_TAB_HELPER_H_ - -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/infobars/core/infobar_manager.h" #import "ios/web/public/web_state_user_data.h" @@ -46,8 +45,9 @@ // The owning tab helper. InfobarOverlayTabHelper* tab_helper_ = nullptr; web::WebState* web_state_ = nullptr; - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - scoped_observer_; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + scoped_observation_{this}; }; // The inserter used to add infobar OverlayRequests to the WebState's queue.
diff --git a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.mm b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.mm index 089f359..02f95c5 100644 --- a/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.mm +++ b/ios/chrome/browser/infobars/overlays/infobar_overlay_tab_helper.mm
@@ -34,11 +34,11 @@ InfobarOverlayTabHelper::OverlayRequestScheduler::OverlayRequestScheduler( web::WebState* web_state, InfobarOverlayTabHelper* tab_helper) - : tab_helper_(tab_helper), web_state_(web_state), scoped_observer_(this) { + : tab_helper_(tab_helper), web_state_(web_state) { DCHECK(tab_helper_); InfoBarManager* manager = InfoBarManagerImpl::FromWebState(web_state); DCHECK(manager); - scoped_observer_.Add(manager); + scoped_observation_.Observe(manager); } InfobarOverlayTabHelper::OverlayRequestScheduler::~OverlayRequestScheduler() = @@ -67,5 +67,6 @@ void InfobarOverlayTabHelper::OverlayRequestScheduler::OnManagerShuttingDown( InfoBarManager* manager) { - scoped_observer_.Remove(manager); + DCHECK(scoped_observation_.IsObservingSource(manager)); + scoped_observation_.Reset(); }
diff --git a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h index ec88eb1..77c5f28 100644 --- a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h +++ b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.h
@@ -7,7 +7,7 @@ #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_cancel_handler.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h" @@ -49,9 +49,9 @@ PlaceholderRequestCancelHandler* cancel_handler_; - ScopedObserver<TranslateOverlayTabHelper, - TranslateOverlayTabHelper::Observer> - scoped_observer_; + base::ScopedObservation<TranslateOverlayTabHelper, + TranslateOverlayTabHelper::Observer> + scoped_observation_{this}; }; // Indicates to the cancel handler that the translation has finished.
diff --git a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.mm b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.mm index 616f3c24..71629ae 100644 --- a/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.mm +++ b/ios/chrome/browser/infobars/overlays/translate_infobar_placeholder_overlay_request_cancel_handler.mm
@@ -37,8 +37,8 @@ PlaceholderRequestCancelHandler::TranslationFinishedObserver:: TranslationFinishedObserver(TranslateOverlayTabHelper* tab_helper, PlaceholderRequestCancelHandler* cancel_handler) - : cancel_handler_(cancel_handler), scoped_observer_(this) { - scoped_observer_.Add(tab_helper); + : cancel_handler_(cancel_handler) { + scoped_observation_.Observe(tab_helper); } PlaceholderRequestCancelHandler::TranslationFinishedObserver:: @@ -51,7 +51,8 @@ void PlaceholderRequestCancelHandler::TranslationFinishedObserver:: TranslateOverlayTabHelperDestroyed(TranslateOverlayTabHelper* tab_helper) { - scoped_observer_.Remove(tab_helper); + DCHECK(scoped_observation_.IsObservingSource(tab_helper)); + scoped_observation_.Reset(); } } // namespace translate_infobar_overlays
diff --git a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h index 3dae119..76d8d9bd 100644 --- a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h +++ b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.h
@@ -9,7 +9,7 @@ #include "base/observer_list.h" #include "base/observer_list_types.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/infobars/core/infobar_manager.h" #include "components/translate/core/browser/translate_infobar_delegate.h" #include "ios/web/public/web_state_observer.h" @@ -74,9 +74,9 @@ translate::TranslateInfoBarDelegate* delegate) override; // Scoped observer that facilitates observing a TranslateInfoBarDelegate. - ScopedObserver<translate::TranslateInfoBarDelegate, - translate::TranslateInfoBarDelegate::Observer> - translate_scoped_observer_; + base::ScopedObservation<translate::TranslateInfoBarDelegate, + translate::TranslateInfoBarDelegate::Observer> + translate_scoped_observation_{this}; // TranslateOverlayTabHelper instance. TranslateOverlayTabHelper* tab_helper_; infobars::InfoBar* translate_infobar_ = nil; @@ -95,8 +95,9 @@ void OnManagerShuttingDown(infobars::InfoBarManager* manager) override; // Scoped observer that facilitates observing an InfoBarManager - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - infobar_manager_scoped_observer_; + base::ScopedObservation<infobars::InfoBarManager, + infobars::InfoBarManager::Observer> + infobar_manager_scoped_observation_{this}; // TranslateOverlayTabHelper instance. TranslateOverlayTabHelper* tab_helper_; }; @@ -114,8 +115,8 @@ void WebStateDestroyed(web::WebState* web_state) override; // Scoped observer that facilitates observing an InfoBarManager - ScopedObserver<web::WebState, web::WebStateObserver> - web_state_scoped_observer_; + base::ScopedObservation<web::WebState, web::WebStateObserver> + web_state_scoped_observation_{this}; // TranslateOverlayTabHelper instance. TranslateOverlayTabHelper* tab_helper_; };
diff --git a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.mm b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.mm index e0312a6..595502a 100644 --- a/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.mm +++ b/ios/chrome/browser/infobars/overlays/translate_overlay_tab_helper.mm
@@ -123,7 +123,7 @@ TranslateOverlayTabHelper::TranslateStepObserver::TranslateStepObserver( TranslateOverlayTabHelper* tab_helper) - : translate_scoped_observer_(this), tab_helper_(tab_helper) {} + : tab_helper_(tab_helper) {} TranslateOverlayTabHelper::TranslateStepObserver::~TranslateStepObserver() = default; @@ -165,14 +165,15 @@ void TranslateOverlayTabHelper::TranslateStepObserver:: OnTranslateInfoBarDelegateDestroyed( translate::TranslateInfoBarDelegate* delegate) { - translate_scoped_observer_.Remove(delegate); + DCHECK(translate_scoped_observation_.IsObservingSource(delegate)); + translate_scoped_observation_.Reset(); translate_infobar_ = nil; } void TranslateOverlayTabHelper::TranslateStepObserver::SetTranslateInfoBar( InfoBarIOS* infobar) { translate_infobar_ = infobar; - translate_scoped_observer_.Add( + translate_scoped_observation_.Observe( infobar->delegate()->AsTranslateInfoBarDelegate()); } @@ -181,11 +182,11 @@ TranslateOverlayTabHelper::TranslateInfobarObserver::TranslateInfobarObserver( web::WebState* web_state, TranslateOverlayTabHelper* tab_helper) - : infobar_manager_scoped_observer_(this), tab_helper_(tab_helper) { + : tab_helper_(tab_helper) { infobars::InfoBarManager* manager = InfoBarManagerImpl::FromWebState(web_state); DCHECK(manager); - infobar_manager_scoped_observer_.Add(manager); + infobar_manager_scoped_observation_.Observe(manager); } TranslateOverlayTabHelper::TranslateInfobarObserver:: @@ -202,7 +203,8 @@ void TranslateOverlayTabHelper::TranslateInfobarObserver::OnManagerShuttingDown( infobars::InfoBarManager* manager) { - infobar_manager_scoped_observer_.Remove(manager); + DCHECK(infobar_manager_scoped_observation_.IsObservingSource(manager)); + infobar_manager_scoped_observation_.Reset(); } #pragma mark - WebStateDestroyedObserver @@ -210,8 +212,8 @@ TranslateOverlayTabHelper::WebStateDestroyedObserver::WebStateDestroyedObserver( web::WebState* web_state, TranslateOverlayTabHelper* tab_helper) - : web_state_scoped_observer_(this), tab_helper_(tab_helper) { - web_state_scoped_observer_.Add(web_state); + : tab_helper_(tab_helper) { + web_state_scoped_observation_.Observe(web_state); } TranslateOverlayTabHelper::WebStateDestroyedObserver:: @@ -219,6 +221,7 @@ void TranslateOverlayTabHelper::WebStateDestroyedObserver::WebStateDestroyed( web::WebState* web_state) { - web_state_scoped_observer_.Remove(web_state); + DCHECK(web_state_scoped_observation_.IsObservingSource(web_state)); + web_state_scoped_observation_.Reset(); tab_helper_->UpdateForWebStateDestroyed(); }
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h index f80cc63..c50aea50 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h
@@ -11,9 +11,21 @@ namespace save_address_profile_infobar_modal_responses { -// Response info used to create dispatched OverlayResponses that notify the -// save address profile infobar to present the address profile settings. -DEFINE_STATELESS_OVERLAY_RESPONSE_INFO(PresentAddressProfileSettings); +// Response info used to create dispatched OverlayResponses once the user +// presses "Save" action on the Edit Modal. +class EditedProfileSaveAction + : public OverlayResponseInfo<EditedProfileSaveAction> { + public: + ~EditedProfileSaveAction() override; + + NSDictionary* profile_data() const { return profile_data_; } + + private: + OVERLAY_USER_DATA_SETUP(EditedProfileSaveAction); + EditedProfileSaveAction(NSDictionary* profileData); + + NSDictionary* profile_data_; +}; } // namespace save_address_profile_infobar_modal_responses
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm index ade0c30..0c0f1b7d 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm
@@ -10,8 +10,13 @@ namespace save_address_profile_infobar_modal_responses { -#pragma mark - PresentAddressProfileSettings +#pragma mark - EditedProfileSaveAction -OVERLAY_USER_DATA_SETUP_IMPL(PresentAddressProfileSettings); +OVERLAY_USER_DATA_SETUP_IMPL(EditedProfileSaveAction); + +EditedProfileSaveAction::EditedProfileSaveAction(NSDictionary* profileData) + : profile_data_(profileData) {} + +EditedProfileSaveAction::~EditedProfileSaveAction() = default; } // save_address_profile_infobar_modal_responses
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h index c3f3d739..071403f4 100644 --- a/ios/chrome/browser/signin/authentication_service.h +++ b/ios/chrome/browser/signin/authentication_service.h
@@ -10,7 +10,7 @@ #import "base/ios/block_types.h" #include "base/memory/weak_ptr.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/keyed_service/core/keyed_service.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/signin/public/base/signin_metrics.h" @@ -234,12 +234,13 @@ // Map between account IDs and their associated MDM error. mutable std::map<CoreAccountId, NSDictionary*> cached_mdm_infos_; - ScopedObserver<ios::ChromeIdentityService, - ios::ChromeIdentityService::Observer> - identity_service_observer_; + base::ScopedObservation<ios::ChromeIdentityService, + ios::ChromeIdentityService::Observer> + identity_service_observation_{this}; - ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer> - identity_manager_observer_; + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + identity_manager_observation_{this}; base::WeakPtrFactory<AuthenticationService> weak_pointer_factory_;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm index 02d28b16..c39ba2e 100644 --- a/ios/chrome/browser/signin/authentication_service.mm +++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -77,8 +77,6 @@ sync_setup_service_(sync_setup_service), identity_manager_(identity_manager), sync_service_(sync_service), - identity_service_observer_(this), - identity_manager_observer_(this), weak_pointer_factory_(this) { DCHECK(pref_service_); DCHECK(sync_setup_service_); @@ -112,14 +110,14 @@ crash_keys::SetCurrentlySignedIn(IsAuthenticated()); - identity_service_observer_.Add( + identity_service_observation_.Observe( ios::GetChromeBrowserProvider()->GetChromeIdentityService()); OnApplicationWillEnterForeground(); } void AuthenticationService::Shutdown() { - identity_manager_observer_.RemoveAll(); + identity_manager_observation_.Reset(); delegate_.reset(); } @@ -127,7 +125,7 @@ if (InForeground()) return; - identity_manager_observer_.Add(identity_manager_); + identity_manager_observation_.Observe(identity_manager_); // As the SSO library does not send notification when the app is in the // background, reload the credentials and check whether any accounts have @@ -172,8 +170,9 @@ // Stop observing |identity_manager_| when in the background. Note that // this allows checking whether the app is in background without having a - // separate bool by using identity_manager_observer_.IsObservingSources(). - identity_manager_observer_.Remove(identity_manager_); + // separate bool by using identity_manager_observation_.IsObserving(). + DCHECK(identity_manager_observation_.IsObservingSource(identity_manager_)); + identity_manager_observation_.Reset(); // Reset the state |have_accounts_changed_while_in_background_| as the // application just entered background. @@ -181,9 +180,9 @@ } bool AuthenticationService::InForeground() const { - // The application is in foreground when |identity_manager_observer_| is + // The application is in foreground when |identity_manager_observation_| is // observing sources. - return identity_manager_observer_.IsObservingSources(); + return identity_manager_observation_.IsObserving(); } void AuthenticationService::SetPromptForSignIn() { @@ -456,8 +455,8 @@ } void AuthenticationService::ResetChromeIdentityServiceObserverForTesting() { - DCHECK(!identity_service_observer_.IsObservingSources()); - identity_service_observer_.Add( + DCHECK(!identity_service_observation_.IsObserving()); + identity_service_observation_.Observe( ios::GetChromeBrowserProvider()->GetChromeIdentityService()); } @@ -542,7 +541,7 @@ } void AuthenticationService::OnChromeIdentityServiceWillBeDestroyed() { - identity_service_observer_.RemoveAll(); + identity_service_observation_.Reset(); } void AuthenticationService::HandleIdentityListChanged() {
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm index 6876ad44..35d5cc2 100644 --- a/ios/chrome/browser/signin/authentication_service_unittest.mm +++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -6,7 +6,6 @@ #include "base/bind.h" #include "base/run_loop.h" -#include "base/scoped_observer.h" #include "base/strings/sys_string_conversions.h" #include "base/test/bind.h" #include "base/test/gtest_util.h"
diff --git a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h index 024253b..b66868b 100644 --- a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h +++ b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h
@@ -8,7 +8,7 @@ #import <Foundation/Foundation.h> #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" // Objective-C protocol mirroring ChromeIdentityService::Observer. @@ -38,9 +38,9 @@ void OnChromeIdentityServiceWillBeDestroyed() override; __weak id<ChromeIdentityServiceObserver> observer_ = nil; - ScopedObserver<ios::ChromeIdentityService, - ios::ChromeIdentityService::Observer> - scoped_observer_{this}; + base::ScopedObservation<ios::ChromeIdentityService, + ios::ChromeIdentityService::Observer> + scoped_observation_{this}; DISALLOW_COPY_AND_ASSIGN(ChromeIdentityServiceObserverBridge); };
diff --git a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm index 1b9cb47..abcb0d0d 100644 --- a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm +++ b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm
@@ -15,7 +15,7 @@ id<ChromeIdentityServiceObserver> observer) : observer_(observer) { DCHECK(observer_); - scoped_observer_.Add( + scoped_observation_.Observe( ios::GetChromeBrowserProvider()->GetChromeIdentityService()); }
diff --git a/ios/chrome/browser/signin/signin_browser_state_info_updater.h b/ios/chrome/browser/signin/signin_browser_state_info_updater.h index 452b0241..10a7981 100644 --- a/ios/chrome/browser/signin/signin_browser_state_info_updater.h +++ b/ios/chrome/browser/signin/signin_browser_state_info_updater.h
@@ -7,7 +7,7 @@ #include "base/files/file_path.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "build/build_config.h" #include "components/keyed_service/core/keyed_service.h" #include "components/signin/core/browser/signin_error_controller.h" @@ -42,10 +42,12 @@ signin::IdentityManager* identity_manager_ = nullptr; SigninErrorController* signin_error_controller_ = nullptr; const base::FilePath browser_state_path_; - ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer> - identity_manager_observer_{this}; - ScopedObserver<SigninErrorController, SigninErrorController::Observer> - signin_error_controller_observer_{this}; + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + identity_manager_observation_{this}; + base::ScopedObservation<SigninErrorController, + SigninErrorController::Observer> + signin_error_controller_observation_{this}; DISALLOW_COPY_AND_ASSIGN(SigninBrowserStateInfoUpdater); };
diff --git a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm index 5293116..45364763 100644 --- a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm +++ b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
@@ -27,9 +27,9 @@ if (!GetApplicationContext()->GetChromeBrowserStateManager()) return; - identity_manager_observer_.Add(identity_manager_); + identity_manager_observation_.Observe(identity_manager_); - signin_error_controller_observer_.Add(signin_error_controller); + signin_error_controller_observation_.Observe(signin_error_controller); UpdateBrowserStateInfo(); // TODO(crbug.com/908457): Call OnErrorChanged() here, to catch any change @@ -40,8 +40,8 @@ SigninBrowserStateInfoUpdater::~SigninBrowserStateInfoUpdater() = default; void SigninBrowserStateInfoUpdater::Shutdown() { - identity_manager_observer_.RemoveAll(); - signin_error_controller_observer_.RemoveAll(); + identity_manager_observation_.Reset(); + signin_error_controller_observation_.Reset(); } void SigninBrowserStateInfoUpdater::UpdateBrowserStateInfo() {
diff --git a/ios/chrome/browser/tabs/tab_helper_delegate_installer.h b/ios/chrome/browser/tabs/tab_helper_delegate_installer.h index ad0f6b6..3c65f39 100644 --- a/ios/chrome/browser/tabs/tab_helper_delegate_installer.h +++ b/ios/chrome/browser/tabs/tab_helper_delegate_installer.h
@@ -6,7 +6,7 @@ #define IOS_CHROME_BROWSER_TABS_TAB_HELPER_DELEGATE_INSTALLER_H_ #include "base/check.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/main/browser_observer.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" @@ -64,7 +64,7 @@ : delegate_(delegate), web_state_list_(web_state_list) { DCHECK(delegate_); DCHECK(web_state_list_); - scoped_observer_.Add(web_state_list_); + scoped_observation_.Observe(web_state_list_); for (int i = 0; i < web_state_list_->count(); ++i) { SetTabHelperDelegate(web_state_list_->GetWebStateAt(i), delegate_); } @@ -78,7 +78,8 @@ for (int i = 0; i < web_state_list_->count(); ++i) { SetTabHelperDelegate(web_state_list_->GetWebStateAt(i), nullptr); } - scoped_observer_.Remove(web_state_list_); + DCHECK(scoped_observation_.IsObservingSource(web_state_list_)); + scoped_observation_.Reset(); web_state_list_ = nullptr; } @@ -113,7 +114,8 @@ // The WebStateList whose Helpers's delegates are being installed. WebStateList* web_state_list_ = nullptr; // Scoped observer for |web_state_list_|. - ScopedObserver<WebStateList, WebStateListObserver> scoped_observer_{this}; + base::ScopedObservation<WebStateList, WebStateListObserver> + scoped_observation_{this}; }; // Helper object that sets up the delegate installer and tears it down @@ -124,7 +126,7 @@ : installer_(installer) { DCHECK(installer_); DCHECK(browser); - scoped_observer_.Add(browser); + scoped_observation_.Observe(browser); } ~BrowserShutdownHelper() override = default; @@ -132,13 +134,14 @@ // BrowserObserver: void BrowserDestroyed(Browser* browser) override { installer_->Disconnect(); - scoped_observer_.Remove(browser); + DCHECK(scoped_observation_.IsObservingSource(browser)); + scoped_observation_.Reset(); } // The installer used to set up the Delegates. Installer* installer_ = nullptr; // Scoped observer for the Browser. - ScopedObserver<Browser, BrowserObserver> scoped_observer_{this}; + base::ScopedObservation<Browser, BrowserObserver> scoped_observation_{this}; }; // Helper object that installs delegates for all the Browser's tab helpers.
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.h b/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.h index 04c18785..9c88cdb 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_BROWSER_OBSERVER_H_ #define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_BROWSER_OBSERVER_H_ -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/main/browser_observer.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h" @@ -25,7 +25,7 @@ // The FullscreenWebStateListObserver passed on construction. FullscreenWebStateListObserver* web_state_list_observer_; // Scoped observer that facilitates observing an BrowserObserver. - ScopedObserver<Browser, BrowserObserver> scoped_observer_; + base::ScopedObservation<Browser, BrowserObserver> scoped_observation_{this}; }; #endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_BROWSER_OBSERVER_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.mm index d921e24..7b5f9de 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_browser_observer.mm
@@ -13,14 +13,13 @@ FullscreenBrowserObserver::FullscreenBrowserObserver( FullscreenWebStateListObserver* web_state_list_observer, Browser* browser) - : web_state_list_observer_(web_state_list_observer), - scoped_observer_(this) { + : web_state_list_observer_(web_state_list_observer) { DCHECK(web_state_list_observer_); // TODO(crbug.com/790886): DCHECK |browser| once FullscreenController is fully // scoped to a Browser. if (browser) { web_state_list_observer_->SetWebStateList(browser->GetWebStateList()); - scoped_observer_.Add(browser); + scoped_observation_.Observe(browser); } } @@ -29,5 +28,6 @@ void FullscreenBrowserObserver::FullscreenBrowserObserver::BrowserDestroyed( Browser* browser) { web_state_list_observer_->SetWebStateList(nullptr); - scoped_observer_.Remove(browser); + DCHECK(scoped_observation_.IsObservingSource(browser)); + scoped_observation_.Reset(); }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h index dddbaa7..12440e9 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_H_ #define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_H_ -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h" @@ -60,7 +60,8 @@ // The observer forwarder. FullscreenControllerObserverForwarder forwarder_; // Scoped observer for |forwarder_|. - ScopedObserver<FullscreenController, FullscreenControllerObserver> observer_; + base::ScopedObservation<FullscreenController, FullscreenControllerObserver> + observation_{&forwarder_}; }; #endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_H_
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.mm index 0bd4a9d..46d55f08 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.mm
@@ -16,9 +16,9 @@ id<FullscreenUIElement> ui_element) : controller_(controller), forwarder_(this, ui_element), - observer_(&forwarder_) { + observation_(&forwarder_) { DCHECK(controller_); - observer_.Add(controller_); + observation_.Observe(controller_); } FullscreenUIUpdater::~FullscreenUIUpdater() = default; @@ -26,7 +26,8 @@ void FullscreenUIUpdater::Disconnect() { if (!controller_) return; - observer_.Remove(controller_); + DCHECK(observation_.IsObservingSource(controller_)); + observation_.Reset(); controller_ = nullptr; }
diff --git a/ios/chrome/browser/ui/infobars/modals/BUILD.gn b/ios/chrome/browser/ui/infobars/modals/BUILD.gn index 552ebc3..099c3b7 100644 --- a/ios/chrome/browser/ui/infobars/modals/BUILD.gn +++ b/ios/chrome/browser/ui/infobars/modals/BUILD.gn
@@ -6,6 +6,7 @@ configs += [ "//build/config/compiler:enable_arc" ] sources = [ "infobar_edit_address_profile_modal_consumer.h", + "infobar_edit_address_profile_modal_delegate.h", "infobar_edit_address_profile_table_view_controller.h", "infobar_edit_address_profile_table_view_controller.mm", "infobar_modal_delegate.h",
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_delegate.h b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_delegate.h new file mode 100644 index 0000000..3f323efe --- /dev/null +++ b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_delegate.h
@@ -0,0 +1,20 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_INFOBARS_MODALS_INFOBAR_EDIT_ADDRESS_PROFILE_MODAL_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_INFOBARS_MODALS_INFOBAR_EDIT_ADDRESS_PROFILE_MODAL_DELEGATE_H_ + +#import <Foundation/Foundation.h> + +#import "ios/chrome/browser/ui/infobars/modals/infobar_modal_delegate.h" + +// Delegate to handle Edit Address Profile Infobar Modal actions. +@protocol InfobarEditAddressProfileModalDelegate <InfobarModalDelegate> + +// Saves the edited profile data. +- (void)saveEditedProfileWithData:(NSDictionary*)profileData; + +@end + +#endif // IOS_CHROME_BROWSER_UI_INFOBARS_MODALS_INFOBAR_EDIT_ADDRESS_PROFILE_MODAL_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller.mm b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller.mm index e97fc9f..6540138 100644 --- a/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller.mm +++ b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller.mm
@@ -5,12 +5,15 @@ #import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller.h" #include "base/mac/foundation_util.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "base/stl_util.h" #include "components/autofill/core/common/autofill_features.h" +#include "ios/chrome/browser/infobars/infobar_metrics_recorder.h" #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" #import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h" #import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h" -#import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_delegate.h" +#import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_delegate.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h" @@ -30,6 +33,7 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) { SectionIdentifierFields = kSectionIdentifierEnumZero, + SectionIdentifierButton }; typedef NS_ENUM(NSInteger, ItemType) { @@ -42,7 +46,10 @@ @interface InfobarEditAddressProfileTableViewController () <UITextFieldDelegate> // The delegate passed to this instance. -@property(nonatomic, weak) id<InfobarSaveAddressProfileModalDelegate> delegate; +@property(nonatomic, weak) id<InfobarEditAddressProfileModalDelegate> delegate; + +// Used to build and record metrics. +@property(nonatomic, strong) InfobarMetricsRecorder* metricsRecorder; // All the data to be displayed in the edit dialog. @property(nonatomic, strong) NSMutableDictionary* profileData; @@ -54,10 +61,12 @@ #pragma mark - Initialization - (instancetype)initWithModalDelegate: - (id<InfobarSaveAddressProfileModalDelegate>)modalDelegate { + (id<InfobarEditAddressProfileModalDelegate>)modalDelegate { self = [super initWithStyle:UITableViewStylePlain]; if (self) { _delegate = modalDelegate; + _metricsRecorder = [[InfobarMetricsRecorder alloc] + initWithType:InfobarType::kInfobarTypeSaveAutofillAddressProfile]; } return self; } @@ -119,13 +128,14 @@ [model addItem:item toSectionWithIdentifier:SectionIdentifierFields]; } + [model addSectionWithIdentifier:SectionIdentifierButton]; TableViewTextButtonItem* saveButton = [[TableViewTextButtonItem alloc] initWithType:ItemTypeSaveButton]; saveButton.textAlignment = NSTextAlignmentNatural; // TODO(crbug.com/1167062): Replace with proper localized string. saveButton.buttonText = @"Test Save"; saveButton.disableButtonIntrinsicWidth = YES; - [model addItem:saveButton toSectionWithIdentifier:SectionIdentifierFields]; + [model addItem:saveButton toSectionWithIdentifier:SectionIdentifierButton]; } #pragma mark - UITableViewDataSource @@ -176,11 +186,35 @@ #pragma mark - Actions - (void)handleCancelButton { - // TODO(crbug.com/1167062): Implement the functionality. + base::RecordAction( + base::UserMetricsAction("MobileMessagesModalCancelledTapped")); + [self.metricsRecorder recordModalEvent:MobileMessagesModalEvent::Canceled]; + [self.delegate dismissInfobarModal:self]; } - (void)didTapSaveButton { - // TODO(crbug.com/1167062): Implement the functionality. + base::RecordAction( + base::UserMetricsAction("MobileMessagesModalAcceptedTapped")); + [self.metricsRecorder recordModalEvent:MobileMessagesModalEvent::Accepted]; + [self updateProfileData]; + [self.delegate saveEditedProfileWithData:self.profileData]; +} + +#pragma mark - Private + +- (void)updateProfileData { + TableViewModel* model = self.tableViewModel; + NSInteger section = + [model sectionForSectionIdentifier:SectionIdentifierFields]; + NSInteger itemCount = [model numberOfItemsInSection:section]; + for (NSInteger itemIndex = 0; itemIndex < itemCount; ++itemIndex) { + NSIndexPath* path = [NSIndexPath indexPathForItem:itemIndex + inSection:section]; + AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( + [model itemAtIndexPath:path]); + self.profileData[[NSNumber numberWithInt:item.autofillUIType]] = + item.textFieldValue; + } } @end
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller_unittest.mm b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller_unittest.mm index 7026be47..6095497 100644 --- a/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_table_view_controller_unittest.mm
@@ -38,6 +38,7 @@ CreateController(); CheckController(); - EXPECT_EQ(1, NumberOfSections()); - EXPECT_EQ(11, NumberOfItemsInSection(0)); + EXPECT_EQ(2, NumberOfSections()); + EXPECT_EQ(10, NumberOfItemsInSection(0)); + EXPECT_EQ(1, NumberOfItemsInSection(1)); }
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn index 8aa4baac..1ce3b31 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn
@@ -28,3 +28,35 @@ "//ui/base", ] } + +source_set("unit_tests") { + testonly = true + sources = + [ "save_address_profile_infobar_modal_overlay_mediator_unittest.mm" ] + + configs += [ "//build/config/compiler:enable_arc" ] + + deps = [ + ":autofill_address_profile", + "//base/test:test_support", + "//components/autofill/core/browser", + "//components/autofill/core/browser:test_support", + "//components/infobars/core", + "//ios/chrome/app/strings:ios_strings_grit", + "//ios/chrome/browser/infobars", + "//ios/chrome/browser/infobars/test", + "//ios/chrome/browser/overlays", + "//ios/chrome/browser/overlays/public/infobar_modal", + "//ios/chrome/browser/overlays/test", + "//ios/chrome/browser/ui/infobars:feature_flags", + "//ios/chrome/browser/ui/infobars/modals", + "//ios/chrome/browser/ui/infobars/modals/test", + "//ios/chrome/browser/ui/infobars/test", + "//ios/chrome/browser/ui/infobars/test", + "//ios/chrome/browser/ui/overlays/test", + "//testing/gmock", + "//testing/gtest", + "//third_party/ocmock", + "//ui/base", + ] +}
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h index ab4ba33..ce561a0 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h
@@ -7,6 +7,7 @@ #import "ios/chrome/browser/ui/overlays/infobar_modal/infobar_modal_overlay_mediator.h" +#import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_delegate.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_delegate.h" #import "ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_delegate.h" @@ -15,7 +16,8 @@ // Mediator that configures the modal UI for save address profile infobar. @interface SaveAddressProfileInfobarModalOverlayMediator - : InfobarModalOverlayMediator <InfobarSaveAddressProfileModalDelegate> + : InfobarModalOverlayMediator <InfobarSaveAddressProfileModalDelegate, + InfobarEditAddressProfileModalDelegate> // The consumer that is configured by this mediator. Setting to a new value // configures the new consumer.
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm index 040576a..e105fa9 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm
@@ -6,6 +6,7 @@ #include "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_consumer.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_consumer.h" #import "ios/chrome/browser/ui/overlays/infobar_modal/infobar_modal_overlay_coordinator+modal_configuration.h" @@ -18,6 +19,7 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; +using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; @interface SaveAddressProfileInfobarModalOverlayMediator () // The save address profile modal config from the request. @@ -90,4 +92,13 @@ [self.saveAddressProfileMediatorDelegate showEditView]; } +#pragma mark - InfobarEditAddressProfileModalDelegate + +- (void)saveEditedProfileWithData:(NSDictionary*)profileData { + [self + dispatchResponse:OverlayResponse::CreateWithInfo<EditedProfileSaveAction>( + profileData)]; + [self dismissOverlay]; +} + @end
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm new file mode 100644 index 0000000..8b55889 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm
@@ -0,0 +1,85 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h" + +#include "base/bind.h" +#include "base/feature_list.h" +#include "base/guid.h" +#include "base/strings/sys_string_conversions.h" +#include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "ios/chrome/browser/infobars/infobar_ios.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h" +#include "ios/chrome/browser/overlays/test/fake_overlay_request_callback_installer.h" +#import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_consumer.h" +#import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_consumer.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#include "third_party/ocmock/gtest_support.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using autofill_address_profile_infobar_overlays:: + SaveAddressProfileModalRequestConfig; +using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; + +// Test fixture for SaveAddressProfileInfobarModalOverlayMediator. +class SaveAddressProfileInfobarModalOverlayMediatorTest : public PlatformTest { + public: + SaveAddressProfileInfobarModalOverlayMediatorTest() + : callback_installer_(&callback_receiver_, + {EditedProfileSaveAction::ResponseSupport()}), + mediator_delegate_( + OCMStrictProtocolMock(@protocol(OverlayRequestMediatorDelegate))) { + autofill::AutofillProfile profile = autofill::test::GetFullProfile(); + std::unique_ptr<autofill::AutofillSaveUpdateAddressProfileDelegateIOS> + delegate = std::make_unique< + autofill::AutofillSaveUpdateAddressProfileDelegateIOS>( + profile, /*original_profile=*/nullptr, /*locale=*/"en-US", + base::DoNothing()); + delegate_ = delegate.get(); + infobar_ = std::make_unique<InfoBarIOS>( + InfobarType::kInfobarTypeSaveAutofillAddressProfile, + std::move(delegate)); + + request_ = + OverlayRequest::CreateWithConfig<SaveAddressProfileModalRequestConfig>( + infobar_.get()); + callback_installer_.InstallCallbacks(request_.get()); + + mediator_ = [[SaveAddressProfileInfobarModalOverlayMediator alloc] + initWithRequest:request_.get()]; + mediator_.delegate = mediator_delegate_; + } + + ~SaveAddressProfileInfobarModalOverlayMediatorTest() override { + EXPECT_CALL(callback_receiver_, CompletionCallback(request_.get())); + EXPECT_OCMOCK_VERIFY(mediator_delegate_); + } + + protected: + autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate_; + std::unique_ptr<InfoBarIOS> infobar_; + MockOverlayRequestCallbackReceiver callback_receiver_; + FakeOverlayRequestCallbackInstaller callback_installer_; + std::unique_ptr<OverlayRequest> request_; + SaveAddressProfileInfobarModalOverlayMediator* mediator_ = nil; + id<OverlayRequestMediatorDelegate> mediator_delegate_ = nil; +}; + +// Tests that calling saveEditedProfileWithData: triggers a +// EditedProfileSaveAction response. +TEST_F(SaveAddressProfileInfobarModalOverlayMediatorTest, EditAction) { + EXPECT_CALL(callback_receiver_, + DispatchCallback(request_.get(), + EditedProfileSaveAction::ResponseSupport())); + OCMExpect([mediator_delegate_ stopOverlayForMediator:mediator_]); + [mediator_ saveEditedProfileWithData:@{}.mutableCopy]; +}
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h index 613aa03..6d1b587 100644 --- a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h +++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.h
@@ -10,7 +10,7 @@ #include "base/callback_list.h" #include "base/macros.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/signin/public/identity_manager/identity_manager.h" class ChromeBrowserState; @@ -45,8 +45,9 @@ __weak id<SyncedSessionsObserver> owner_ = nil; signin::IdentityManager* identity_manager_ = nullptr; - ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer> - identity_manager_observer_; + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + identity_manager_observation_{this}; base::CallbackListSubscription foreign_session_updated_subscription_; DISALLOW_COPY_AND_ASSIGN(SyncedSessionsObserverBridge);
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm index 1893f124..8fe73cf 100644 --- a/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm +++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions_bridge.mm
@@ -24,9 +24,8 @@ ChromeBrowserState* browserState) : owner_(owner), identity_manager_( - IdentityManagerFactory::GetForBrowserState(browserState)), - identity_manager_observer_(this) { - identity_manager_observer_.Add(identity_manager_); + IdentityManagerFactory::GetForBrowserState(browserState)) { + identity_manager_observation_.Observe(identity_manager_); // base::Unretained() is safe below because the subscription itself is a class // member field and handles destruction well.
diff --git a/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm b/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm index a0965f6..99da18f6 100644 --- a/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm +++ b/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm
@@ -4,7 +4,7 @@ #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" #include "components/content_settings/core/browser/content_settings_details.h" #include "components/content_settings/core/browser/content_settings_observer.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -32,8 +32,9 @@ namespace { -typedef ScopedObserver<HostContentSettingsMap, content_settings::Observer> - ContentSettingsObserver; +typedef base::ScopedObservation<HostContentSettingsMap, + content_settings::Observer> + ContentSettingsObseration; class ContentSettingsObserverBridge : public content_settings::Observer { public: @@ -84,7 +85,7 @@ ContentSettingsType _settingID; scoped_refptr<HostContentSettingsMap> _settingsMap; std::unique_ptr<ContentSettingsObserverBridge> _adaptor; - std::unique_ptr<ContentSettingsObserver> _content_settings_observer; + std::unique_ptr<ContentSettingsObseration> _content_settings_observer; } @synthesize settingID = _settingID; @@ -103,8 +104,8 @@ // Listen for changes to the content setting. _adaptor.reset(new ContentSettingsObserverBridge(self)); _content_settings_observer.reset( - new ContentSettingsObserver(_adaptor.get())); - _content_settings_observer->Add(settingsMap); + new ContentSettingsObseration(_adaptor.get())); + _content_settings_observer->Observe(settingsMap); } return self; }
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 900f9695..a69e070 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -291,6 +291,7 @@ "//ios/chrome/browser/ui/overlays/infobar_banner/save_card:unit_tests", "//ios/chrome/browser/ui/overlays/infobar_banner/translate:unit_tests", "//ios/chrome/browser/ui/overlays/infobar_modal:unit_tests", + "//ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile:unit_tests", "//ios/chrome/browser/ui/overlays/infobar_modal/passwords:unit_tests", "//ios/chrome/browser/ui/overlays/infobar_modal/save_card:unit_tests", "//ios/chrome/browser/ui/overlays/infobar_modal/translate:unit_tests",
diff --git a/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.mm b/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.mm index 87a64590..ddccdd0 100644 --- a/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.mm +++ b/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.mm
@@ -115,7 +115,7 @@ return false; }); if (!GetMatchingDomain(navigated_domain, engaged_sites, in_target_allowlist, - &matched_domain, &match_type)) { + proto, &matched_domain, &match_type)) { if (base::FeatureList::IsEnabled( lookalikes::features::kLookalikeInterstitialForPunycode) && ShouldBlockBySpoofCheckResult(navigated_domain)) {
diff --git a/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper_unittest.mm b/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper_unittest.mm index 9c91f3c..dc109d61 100644 --- a/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper_unittest.mm +++ b/ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper_unittest.mm
@@ -101,7 +101,7 @@ TEST_F(LookalikeUrlTabHelperTest, ShouldAllowResponseForAllowlistedDomains) { GURL lookalike_url("https://xn--googl-fsa.com/"); reputation::InitializeSafetyTipConfig(); - reputation::SetSafetyTipAllowlistPatterns({"xn--googl-fsa.com/"}, {}); + reputation::SetSafetyTipAllowlistPatterns({"xn--googl-fsa.com/"}, {}, {}); EXPECT_TRUE(ShouldAllowResponseUrl(lookalike_url, /*main_frame=*/true) .ShouldAllowNavigation());
diff --git a/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h b/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h index 5cda2ade..712bdef9 100644 --- a/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h +++ b/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h
@@ -9,7 +9,7 @@ #import "ios/public/provider/chrome/browser/discover_feed/discover_feed_provider.h" -#include "base/scoped_observer.h" +#include "base/scoped_observation.h" // Implement this protocol and pass your implementation into an // DiscoveFeedObserverBridge object to receive DiscoverFeed observer @@ -43,8 +43,8 @@ void OnDiscoverFeedModelRecreated() override; __weak id<DiscoverFeedObserverBridgeDelegate> observer_; - ScopedObserver<DiscoverFeedProvider, DiscoverFeedProvider::Observer> - scoped_observer_{this}; + base::ScopedObservation<DiscoverFeedProvider, DiscoverFeedProvider::Observer> + scoped_observation_{this}; }; #endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_DISCOVER_FEED_DISCOVER_FEED_OBSERVER_BRIDGE_H_
diff --git a/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.mm b/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.mm index 40011994..8fc34da2 100644 --- a/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.mm +++ b/ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.mm
@@ -13,7 +13,7 @@ DiscoverFeedObserverBridge::DiscoverFeedObserverBridge( id<DiscoverFeedObserverBridgeDelegate> observer) : observer_(observer) { - scoped_observer_.Add( + scoped_observation_.Observe( ios::GetChromeBrowserProvider()->GetDiscoverFeedProvider()); }
diff --git a/media/capture/video/fuchsia/video_capture_device_fuchsia.cc b/media/capture/video/fuchsia/video_capture_device_fuchsia.cc index 4538182d..3315956 100644 --- a/media/capture/video/fuchsia/video_capture_device_fuchsia.cc +++ b/media/capture/video/fuchsia/video_capture_device_fuchsia.cc
@@ -179,7 +179,6 @@ void VideoCaptureDeviceFuchsia::DisconnectStream() { stream_.Unbind(); - buffer_collection_creator_.reset(); buffer_collection_.reset(); buffers_.clear(); frame_size_.reset(); @@ -251,40 +250,24 @@ // Initialize the new collection. fuchsia::sysmem::BufferCollectionTokenPtr token; token.Bind(std::move(token_handle)); - buffer_collection_creator_ = - sysmem_allocator_.MakeBufferPoolCreatorFromToken(std::move(token)); // Request just one buffer in collection constraints: each frame is copied as // soon as it's received. const size_t kMaxUsedOutputFrames = 1; + // This is not an actual device driver, so the priority should be > 1. It's + // also not a high-level system, so the name should be < 100. + constexpr uint32_t kNamePriority = 10; + // Sysmem calculates buffer size based on image constraints, so it doesn't // need to be specified explicitly. fuchsia::sysmem::BufferCollectionConstraints constraints = VmoBuffer::GetRecommendedConstraints(kMaxUsedOutputFrames, /*min_buffer_size=*/absl::nullopt, /*writable=*/false); - // This is not an actual device driver, so the priority should be > 1. It's - // also not a high-level system, so the name should be < 100. - constexpr uint32_t kNamePriority = 10; - buffer_collection_creator_->SetName(kNamePriority, - "CrVideoCaptureDeviceFuchsia"); - buffer_collection_creator_->Create( - std::move(constraints), - base::BindOnce(&VideoCaptureDeviceFuchsia::OnBufferCollectionCreated, - base::Unretained(this))); -} - -void VideoCaptureDeviceFuchsia::OnBufferCollectionCreated( - std::unique_ptr<SysmemBufferPool> collection) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Buffer collection allocation has failed. This case is not treated as an - // error because the camera may create a new collection. - if (!collection) - return; - - buffer_collection_ = std::move(collection); + buffer_collection_ = sysmem_allocator_.BindSharedCollection(std::move(token)); + buffer_collection_->Initialize(std::move(constraints), "CrVideoCaptureDevice", + kNamePriority); buffer_collection_->AcquireBuffers(base::BindOnce( &VideoCaptureDeviceFuchsia::OnBuffersAcquired, base::Unretained(this))); }
diff --git a/media/capture/video/fuchsia/video_capture_device_fuchsia.h b/media/capture/video/fuchsia/video_capture_device_fuchsia.h index 76d7bb21..2df3beef 100644 --- a/media/capture/video/fuchsia/video_capture_device_fuchsia.h +++ b/media/capture/video/fuchsia/video_capture_device_fuchsia.h
@@ -12,7 +12,7 @@ #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "media/capture/video/video_capture_device.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" +#include "media/fuchsia/common/sysmem_client.h" #include "media/fuchsia/common/vmo_buffer.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -77,10 +77,7 @@ fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token_handle); - // Callback for SysmemBufferPool::Creator. - void OnBufferCollectionCreated(std::unique_ptr<SysmemBufferPool> collection); - - // Callback for SysmemBufferPool::AcquireBuffers(). + // Callback for SysmemCollectionClient::AcquireBuffers(). void OnBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings); @@ -97,9 +94,8 @@ std::unique_ptr<Client> client_; - media::BufferAllocator sysmem_allocator_; - std::unique_ptr<SysmemBufferPool::Creator> buffer_collection_creator_; - std::unique_ptr<SysmemBufferPool> buffer_collection_; + SysmemAllocatorClient sysmem_allocator_; + std::unique_ptr<SysmemCollectionClient> buffer_collection_; std::vector<VmoBuffer> buffers_; fuchsia::sysmem::ImageFormatConstraints buffers_format_;
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc index 72bdfe7..44ad52ac 100644 --- a/media/filters/fuchsia/fuchsia_video_decoder.cc +++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -41,7 +41,7 @@ #include "media/fuchsia/cdm/fuchsia_decryptor.h" #include "media/fuchsia/cdm/fuchsia_stream_decryptor.h" #include "media/fuchsia/common/stream_processor_helper.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" +#include "media/fuchsia/common/sysmem_client.h" #include "media/fuchsia/common/vmo_buffer_writer_queue.h" #include "third_party/libyuv/include/libyuv/video_common.h" #include "ui/gfx/buffer_types.h" @@ -243,11 +243,12 @@ // Called on errors to shutdown the decoder and notify the client. void OnError(); - // Callback for |input_buffer_collection_creator_->Create()|. - void OnInputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); + // Callback for |input_buffer_collection_->GetSharedToken()|. + void SetInputBufferCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token); - // Callback for |input_buffer_collection_->CreateWriter()|. - void OnBuffersAcquired( + // Callback for |input_buffer_collection_->AcquireBuffers()|. + void OnInputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings); @@ -292,7 +293,7 @@ absl::optional<fuchsia::media::StreamBufferConstraints> decoder_input_constraints_; - BufferAllocator sysmem_allocator_; + SysmemAllocatorClient sysmem_allocator_; std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_; uint64_t stream_lifetime_ordinal_ = 1; @@ -310,8 +311,7 @@ // Input buffers for |decoder_|. uint64_t input_buffer_lifetime_ordinal_ = 1; - std::unique_ptr<SysmemBufferPool::Creator> input_buffer_collection_creator_; - std::unique_ptr<SysmemBufferPool> input_buffer_collection_; + std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; base::flat_map<size_t, InputDecoderPacket> in_flight_input_packets_; // Output buffers for |decoder_|. @@ -590,14 +590,20 @@ ReleaseInputBuffers(); - // Create buffer constrains for the input buffer collection. - size_t num_tokens; - fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; + input_buffer_collection_ = sysmem_allocator_.AllocateNewCollection(); + + input_buffer_collection_->CreateSharedToken(base::BindOnce( + &FuchsiaVideoDecoder::SetInputBufferCollection, base::Unretained(this))); if (decryptor_) { - // For encrypted streams the sysmem buffer collection is used for decryptor - // output and decoder input. It is not used directly. - num_tokens = 2; + input_buffer_collection_->CreateSharedToken(base::BindOnce( + &FuchsiaSecureStreamDecryptor::SetOutputBufferCollectionToken, + base::Unretained(decryptor_.get()))); + } + + // Create buffer constrains for the input buffer collection. + fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; + if (decryptor_) { buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; buffer_constraints.min_buffer_count = kNumInputBuffers; buffer_constraints.has_buffer_memory_constraints = true; @@ -608,46 +614,30 @@ buffer_constraints.buffer_memory_constraints.inaccessible_domain_supported = true; } else { - num_tokens = 1; buffer_constraints = VmoBuffer::GetRecommendedConstraints( kNumInputBuffers, kInputBufferSize, /*writable=*/true); } - input_buffer_collection_creator_ = - sysmem_allocator_.MakeBufferPoolCreator(num_tokens); - input_buffer_collection_creator_->Create( - std::move(buffer_constraints), - base::BindOnce(&FuchsiaVideoDecoder::OnInputBufferPoolCreated, - base::Unretained(this))); + input_buffer_collection_->Initialize(std::move(buffer_constraints), + "CrVideoDecoderInput"); + + if (!decryptor_) { + input_buffer_collection_->AcquireBuffers(base::BindOnce( + &FuchsiaVideoDecoder::OnInputBuffersAcquired, base::Unretained(this))); + } } -void FuchsiaVideoDecoder::OnInputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { - if (!pool) { - DLOG(ERROR) << "Fail to allocate input buffers for the codec."; - OnError(); - return; - } - - input_buffer_collection_ = std::move(pool); - +void FuchsiaVideoDecoder::SetInputBufferCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token) { fuchsia::media::StreamBufferPartialSettings settings; settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_); settings.set_buffer_constraints_version_ordinal( decoder_input_constraints_->buffer_constraints_version_ordinal()); - settings.set_sysmem_token(input_buffer_collection_->TakeToken()); + settings.set_sysmem_token(std::move(token)); decoder_->SetInputBufferPartialSettings(std::move(settings)); - - if (decryptor_) { - decryptor_->SetOutputBufferCollectionToken( - input_buffer_collection_->TakeToken()); - } else { - input_buffer_collection_->AcquireBuffers(base::BindOnce( - &FuchsiaVideoDecoder::OnBuffersAcquired, base::Unretained(this))); - } } -void FuchsiaVideoDecoder::OnBuffersAcquired( +void FuchsiaVideoDecoder::OnInputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings) { if (buffers.empty()) { @@ -1056,7 +1046,6 @@ void FuchsiaVideoDecoder::ReleaseInputBuffers() { input_writer_queue_.ResetBuffers(); - input_buffer_collection_creator_.reset(); input_buffer_collection_.reset(); // |in_flight_input_packets_| must be destroyed after
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc index 58a60ad..098ebd4 100644 --- a/media/filters/stream_parser_factory.cc +++ b/media/filters/stream_parser_factory.cc
@@ -488,6 +488,18 @@ bool found_codec = false; std::string codec_id = codecs[j]; for (int k = 0; type_info.codecs[k]; ++k) { + // Only check a codec pattern if there is one to check. Some types, + // like audio/mpeg and audio/aac require there be no codecs parameter, + // and instead have implicit codec. If a codec is provided for such a + // type then it is not supported by MSE. We don't check any other + // potential matches because none should be configured. + if (!type_info.codecs[k]->pattern) { + DCHECK(k == 0 && !type_info.codecs[1]) + << "For a type with implicit codec, then only one codec must " + "be configured"; + break; + } + if (base::MatchPattern(codec_id, type_info.codecs[k]->pattern) && (!type_info.codecs[k]->validator || type_info.codecs[k]->validator(codec_id, media_log))) {
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc index 26f5498..586d22ac 100644 --- a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc +++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc
@@ -131,15 +131,16 @@ const fuchsia::media::StreamBufferConstraints& stream_constraints) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto buffer_constraints = VmoBuffer::GetRecommendedConstraints( - kMinBufferCount, min_buffer_size_, /*writable=*/true); - - input_pool_creator_ = - allocator_.MakeBufferPoolCreator(/*num_shared_token=*/1); - - input_pool_creator_->Create( - std::move(buffer_constraints), - base::BindOnce(&FuchsiaStreamDecryptorBase::OnInputBufferPoolCreated, + input_buffer_collection_ = allocator_.AllocateNewCollection(); + input_buffer_collection_->CreateSharedToken( + base::BindOnce(&StreamProcessorHelper::CompleteInputBuffersAllocation, + base::Unretained(&processor_))); + input_buffer_collection_->Initialize( + VmoBuffer::GetRecommendedConstraints(kMinBufferCount, min_buffer_size_, + /*writable=*/true), + "CrStreamDecryptorInput"); + input_buffer_collection_->AcquireBuffers( + base::BindOnce(&FuchsiaStreamDecryptorBase::OnInputBuffersAcquired, base::Unretained(this))); } @@ -148,27 +149,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -void FuchsiaStreamDecryptorBase::OnInputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!pool) { - DLOG(ERROR) << "Fail to allocate input buffer."; - OnError(); - return; - } - - input_pool_ = std::move(pool); - - // Provide token before enabling writer. Tokens must be provided to - // StreamProcessor before getting the allocated buffers. - processor_.CompleteInputBuffersAllocation(input_pool_->TakeToken()); - - input_pool_->AcquireBuffers( - base::BindOnce(&FuchsiaStreamDecryptorBase::OnInputBuffersAcquired, - base::Unretained(this))); -} - void FuchsiaStreamDecryptorBase::OnInputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings) { @@ -248,12 +228,16 @@ void FuchsiaClearStreamDecryptor::AllocateOutputBuffers( const fuchsia::media::StreamBufferConstraints& stream_constraints) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - output_pool_creator_ = - allocator_.MakeBufferPoolCreator(1 /* num_shared_token */); - output_pool_creator_->Create( + output_buffer_collection_ = allocator_.AllocateNewCollection(); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation, + base::Unretained(&processor_))); + output_buffer_collection_->Initialize( VmoBuffer::GetRecommendedConstraints(kMinBufferCount, min_buffer_size_, /*writable=*/false), - base::BindOnce(&FuchsiaClearStreamDecryptor::OnOutputBufferPoolCreated, + "CrFuchsiaStreamDecryptor"); + output_buffer_collection_->AcquireBuffers( + base::BindOnce(&FuchsiaClearStreamDecryptor::OnOutputBuffersAcquired, base::Unretained(this))); } @@ -269,12 +253,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(decrypt_cb_); - DCHECK(output_buffers_.empty()); - if (!output_pool_->is_live()) { - DLOG(ERROR) << "Output buffer pool is dead."; - return; - } - size_t buffer_index = packet.buffer_index(); if (buffer_index >= output_buffers_.size()) { DLOG(ERROR) << "Received output packet with invalid buffer index: " @@ -352,27 +330,6 @@ std::move(decrypt_cb_).Run(Decryptor::kError, nullptr); } -void FuchsiaClearStreamDecryptor::OnOutputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!pool) { - LOG(ERROR) << "Fail to allocate output buffer."; - OnError(); - return; - } - - output_pool_ = std::move(pool); - - // Provide token before enabling reader. Tokens must be provided to - // StreamProcessor before getting the allocated buffers. - processor_.CompleteOutputBuffersAllocation(output_pool_->TakeToken()); - - output_pool_->AcquireBuffers( - base::BindOnce(&FuchsiaClearStreamDecryptor::OnOutputBuffersAcquired, - base::Unretained(this))); -} - void FuchsiaClearStreamDecryptor::OnOutputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings) {
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.h b/media/fuchsia/cdm/fuchsia_stream_decryptor.h index 067b8212..377c69a 100644 --- a/media/fuchsia/cdm/fuchsia_stream_decryptor.h +++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.h
@@ -12,7 +12,7 @@ #include "base/sequence_checker.h" #include "media/base/decryptor.h" #include "media/fuchsia/common/stream_processor_helper.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" +#include "media/fuchsia/common/sysmem_client.h" #include "media/fuchsia/common/vmo_buffer_writer_queue.h" namespace media { @@ -39,7 +39,7 @@ const size_t min_buffer_size_; - BufferAllocator allocator_; + SysmemAllocatorClient allocator_; VmoBufferWriterQueue input_writer_queue_; @@ -49,7 +49,6 @@ SEQUENCE_CHECKER(sequence_checker_); private: - void OnInputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); void OnInputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings); @@ -57,8 +56,7 @@ StreamProcessorHelper::IoPacket packet); void ProcessEndOfStream(); - std::unique_ptr<SysmemBufferPool::Creator> input_pool_creator_; - std::unique_ptr<SysmemBufferPool> input_pool_; + std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; DISALLOW_COPY_AND_ASSIGN(FuchsiaStreamDecryptorBase); }; @@ -89,15 +87,13 @@ void OnNoKey() final; void OnError() final; - void OnOutputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); void OnOutputBuffersAcquired( std::vector<VmoBuffer> buffers, const fuchsia::sysmem::SingleBufferSettings& buffer_settings); Decryptor::DecryptCB decrypt_cb_; - std::unique_ptr<SysmemBufferPool::Creator> output_pool_creator_; - std::unique_ptr<SysmemBufferPool> output_pool_; + std::unique_ptr<SysmemCollectionClient> output_buffer_collection_; std::vector<VmoBuffer> output_buffers_; // Used to re-assemble decrypted output that was split between multiple sysmem
diff --git a/media/fuchsia/common/BUILD.gn b/media/fuchsia/common/BUILD.gn index bda259b..cd3f1c12 100644 --- a/media/fuchsia/common/BUILD.gn +++ b/media/fuchsia/common/BUILD.gn
@@ -8,8 +8,8 @@ sources = [ "stream_processor_helper.cc", "stream_processor_helper.h", - "sysmem_buffer_pool.cc", - "sysmem_buffer_pool.h", + "sysmem_client.cc", + "sysmem_client.h", "vmo_buffer.cc", "vmo_buffer.h", "vmo_buffer_writer_queue.cc",
diff --git a/media/fuchsia/common/sysmem_buffer_pool.cc b/media/fuchsia/common/sysmem_buffer_pool.cc deleted file mode 100644 index de58ebf..0000000 --- a/media/fuchsia/common/sysmem_buffer_pool.cc +++ /dev/null
@@ -1,189 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/fuchsia/common/sysmem_buffer_pool.h" - -#include <zircon/rights.h> -#include <algorithm> - -#include "base/bind.h" -#include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/process_context.h" -#include "base/process/process_handle.h" -#include "media/fuchsia/common/vmo_buffer.h" - -namespace media { - -SysmemBufferPool::Creator::Creator( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens) - : collection_(std::move(collection)), - shared_tokens_(std::move(shared_tokens)) { - collection_.set_error_handler( - [this](zx_status_t status) { - ZX_DLOG(ERROR, status) - << "Connection to BufferCollection was disconnected."; - collection_.Unbind(); - - if (create_cb_) - std::move(create_cb_).Run(nullptr); - }); -} - -SysmemBufferPool::Creator::~Creator() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void SysmemBufferPool::Creator::SetName(uint32_t priority, - base::StringPiece name) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_cb_); - collection_->SetName(priority, std::string(name)); -} - -void SysmemBufferPool::Creator::Create( - fuchsia::sysmem::BufferCollectionConstraints constraints, - CreateCB create_cb) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_cb_); - create_cb_ = std::move(create_cb); - // BufferCollection needs to be synchronized to ensure that all token - // duplicate requests have been processed and sysmem knows about all clients - // that will be using this buffer collection. - collection_->Sync([this, constraints = std::move(constraints)]() mutable { - bool writable = constraints.usage.cpu & fuchsia::sysmem::cpuUsageWrite; - - collection_->SetConstraints(true /* has constraints */, - std::move(constraints)); - - DCHECK(create_cb_); - std::move(create_cb_) - .Run(std::make_unique<SysmemBufferPool>( - std::move(collection_), std::move(shared_tokens_), writable)); - }); -} - -SysmemBufferPool::SysmemBufferPool( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens, - bool writable) - : collection_(std::move(collection)), - shared_tokens_(std::move(shared_tokens)), - writable_(writable) { - collection_.set_error_handler([this](zx_status_t status) { - ZX_LOG(ERROR, status) << "fuchsia.sysmem.BufferCollection disconnected."; - OnError(); - }); -} - -SysmemBufferPool::~SysmemBufferPool() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (collection_) - collection_->Close(); -} - -fuchsia::sysmem::BufferCollectionTokenPtr SysmemBufferPool::TakeToken() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!shared_tokens_.empty()); - auto token = std::move(shared_tokens_.back()); - shared_tokens_.pop_back(); - return token; -} - -void SysmemBufferPool::AcquireBuffers(AcquireBuffersCB cb) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!acquire_buffers_cb_); - acquire_buffers_cb_ = std::move(cb); - collection_->WaitForBuffersAllocated( - fit::bind_member(this, &SysmemBufferPool::OnBuffersAllocated)); -} - -void SysmemBufferPool::OnBuffersAllocated( - zx_status_t status, - fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "Fail to allocate sysmem buffers."; - OnError(); - return; - } - - if (acquire_buffers_cb_) { - auto buffers = VmoBuffer::CreateBuffersFromSysmemCollection( - &buffer_collection_info, writable_); - - std::move(acquire_buffers_cb_) - .Run(std::move(buffers), buffer_collection_info.settings); - } -} - -void SysmemBufferPool::OnError() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - collection_.Unbind(); - if (acquire_buffers_cb_) - std::move(acquire_buffers_cb_).Run({}, {}); -} - -BufferAllocator::BufferAllocator(base::StringPiece client_name) { - allocator_ = base::ComponentContextForProcess() - ->svc() - ->Connect<fuchsia::sysmem::Allocator>(); - - allocator_->SetDebugClientInfo(std::string(client_name), - base::GetCurrentProcId()); - - allocator_.set_error_handler([](zx_status_t status) { - // Just log a warning. We will handle BufferCollection the failure when - // trying to create a new BufferCollection. - ZX_DLOG(WARNING, status) - << "The fuchsia.sysmem.Allocator channel was disconnected."; - }); -} - -BufferAllocator::~BufferAllocator() = default; - -fuchsia::sysmem::BufferCollectionTokenPtr BufferAllocator::CreateNewToken() { - fuchsia::sysmem::BufferCollectionTokenPtr collection_token; - allocator_->AllocateSharedCollection(collection_token.NewRequest()); - return collection_token; -} - -std::unique_ptr<SysmemBufferPool::Creator> -BufferAllocator::MakeBufferPoolCreator(size_t num_of_tokens) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Create a new sysmem buffer collection token for the allocated buffers. - fuchsia::sysmem::BufferCollectionTokenPtr collection_token = CreateNewToken(); - - // Create collection token for sharing with other components. - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens; - for (size_t i = 0; i < num_of_tokens; i++) { - fuchsia::sysmem::BufferCollectionTokenPtr token; - collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS, token.NewRequest()); - shared_tokens.push_back(std::move(token)); - } - - fuchsia::sysmem::BufferCollectionPtr buffer_collection; - - // Convert the token to a BufferCollection connection. - allocator_->BindSharedCollection(std::move(collection_token), - buffer_collection.NewRequest()); - - return std::make_unique<SysmemBufferPool::Creator>( - std::move(buffer_collection), std::move(shared_tokens)); -} - -std::unique_ptr<SysmemBufferPool::Creator> -BufferAllocator::MakeBufferPoolCreatorFromToken( - fuchsia::sysmem::BufferCollectionTokenPtr token) { - fuchsia::sysmem::BufferCollectionPtr buffer_collection; - allocator_->BindSharedCollection(std::move(token), - buffer_collection.NewRequest()); - return std::make_unique<SysmemBufferPool::Creator>( - std::move(buffer_collection), - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr>{}); -} - -} // namespace media
diff --git a/media/fuchsia/common/sysmem_buffer_pool.h b/media/fuchsia/common/sysmem_buffer_pool.h deleted file mode 100644 index 73618c4f..0000000 --- a/media/fuchsia/common/sysmem_buffer_pool.h +++ /dev/null
@@ -1,127 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_ -#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_ - -#include <fuchsia/media/cpp/fidl.h> -#include <fuchsia/sysmem/cpp/fidl.h> -#include <lib/sys/cpp/component_context.h> - -#include <list> -#include <vector> - -#include "base/callback.h" -#include "base/containers/span.h" -#include "base/macros.h" -#include "base/threading/thread_checker.h" - -namespace media { - -class VmoBuffer; - -// Pool of buffers allocated by sysmem. It owns BufferCollection. It doesn't -// provide any function read/write the buffers. Call should use -// ReadableBufferPool/WritableBufferPool for read/write. -class SysmemBufferPool { - public: - // Callback for AcquireBuffers(). Called with an empty |buffers| if buffers - // allocation failed. - using AcquireBuffersCB = base::OnceCallback<void( - std::vector<VmoBuffer> buffers, - const fuchsia::sysmem::SingleBufferSettings& settings)>; - - // Creates SysmemBufferPool asynchronously. It also owns the channel to - // fuchsia services. - class Creator { - public: - using CreateCB = - base::OnceCallback<void(std::unique_ptr<SysmemBufferPool>)>; - Creator( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens); - ~Creator(); - - // Sets the name of the created buffers. Priority is a number used to choose - // which name to use when multiple clients set names. Must be called before - // Create. See fuchsia.sysmem/BufferCollection.SetName for a description of - // the arguments. - void SetName(uint32_t priority, base::StringPiece name); - void Create(fuchsia::sysmem::BufferCollectionConstraints constraints, - CreateCB build_cb); - - private: - fuchsia::sysmem::BufferCollectionPtr collection_; - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens_; - CreateCB create_cb_; - - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(Creator); - }; - - SysmemBufferPool( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens, - bool writable); - ~SysmemBufferPool(); - - fuchsia::sysmem::BufferCollectionTokenPtr TakeToken(); - - // Create VmoBuffers to access raw memory. - void AcquireBuffers(AcquireBuffersCB cb); - - // Returns if this object is still usable. Caller must check this before - // calling SysmemBufferReader/Writer APIs. - bool is_live() const { return collection_.is_bound(); } - - private: - friend class BufferAllocator; - - void OnBuffersAllocated( - zx_status_t status, - fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); - void OnError(); - - fuchsia::sysmem::BufferCollectionPtr collection_; - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens_; - const bool writable_; - - AcquireBuffersCB acquire_buffers_cb_; - - // FIDL interfaces are thread-affine (see crbug.com/1012875). - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(SysmemBufferPool); -}; - -// Wrapper of sysmem Allocator. -class BufferAllocator { - public: - explicit BufferAllocator(base::StringPiece client_name); - ~BufferAllocator(); - - fuchsia::sysmem::BufferCollectionTokenPtr CreateNewToken(); - - std::unique_ptr<SysmemBufferPool::Creator> MakeBufferPoolCreator( - size_t num_shared_token); - - std::unique_ptr<SysmemBufferPool::Creator> MakeBufferPoolCreatorFromToken( - fuchsia::sysmem::BufferCollectionTokenPtr token); - - // TODO(crbug.com/1131183): Update FuchsiaVideoDecoder to use SysmemBufferPool - // and remove this function. - fuchsia::sysmem::Allocator* raw() { return allocator_.get(); } - - private: - fuchsia::sysmem::AllocatorPtr allocator_; - - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(BufferAllocator); -}; - -} // namespace media - -#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_
diff --git a/media/fuchsia/common/sysmem_client.cc b/media/fuchsia/common/sysmem_client.cc new file mode 100644 index 0000000..f2a198df --- /dev/null +++ b/media/fuchsia/common/sysmem_client.cc
@@ -0,0 +1,163 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/fuchsia/common/sysmem_client.h" + +#include <lib/sys/cpp/component_context.h> +#include <zircon/rights.h> + +#include <algorithm> + +#include "base/bind.h" +#include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" +#include "base/process/process_handle.h" +#include "media/fuchsia/common/vmo_buffer.h" + +namespace media { + +SysmemCollectionClient::SysmemCollectionClient( + fuchsia::sysmem::Allocator* allocator, + fuchsia::sysmem::BufferCollectionTokenPtr collection_token) + : allocator_(allocator), collection_token_(std::move(collection_token)) { + DCHECK(allocator_); + DCHECK(collection_token_); +} + +SysmemCollectionClient::~SysmemCollectionClient() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void SysmemCollectionClient::Initialize( + fuchsia::sysmem::BufferCollectionConstraints constraints, + base::StringPiece name, + uint32_t name_priority) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + writable_ = (constraints.usage.cpu & fuchsia::sysmem::cpuUsageWrite) == + fuchsia::sysmem::cpuUsageWrite; + + allocator_->BindSharedCollection(std::move(collection_token_), + collection_.NewRequest()); + + collection_.set_error_handler( + fit::bind_member(this, &SysmemCollectionClient::OnError)); + collection_->SetName(name_priority, std::string(name)); + + // If Sync() is not required then constraints can be set immediately. + if (sync_completion_closures_.empty()) { + collection_->SetConstraints(/*have_constraints=*/true, + std::move(constraints)); + return; + } + + sync_completion_closures_.push_back( + base::BindOnce(&fuchsia::sysmem::BufferCollection::SetConstraints, + base::Unretained(collection_.get()), + /*have_constraints=*/true, std::move(constraints))); + collection_->Sync( + fit::bind_member(this, &SysmemCollectionClient::OnSyncComplete)); +} + +void SysmemCollectionClient::CreateSharedToken(GetSharedTokenCB cb) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(collection_token_); + + fuchsia::sysmem::BufferCollectionTokenPtr token; + collection_token_->Duplicate(ZX_RIGHT_SAME_RIGHTS, token.NewRequest()); + + sync_completion_closures_.push_back( + base::BindOnce(std::move(cb), std::move(token))); +} + +void SysmemCollectionClient::AcquireBuffers(AcquireBuffersCB cb) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!collection_token_); + + if (!collection_) { + std::move(cb).Run({}, {}); + return; + } + + acquire_buffers_cb_ = std::move(cb); + collection_->WaitForBuffersAllocated( + fit::bind_member(this, &SysmemCollectionClient::OnBuffersAllocated)); +} + +void SysmemCollectionClient::OnSyncComplete() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + std::vector<base::OnceClosure> sync_closures = + std::move(sync_completion_closures_); + for (auto& cb : sync_closures) { + std::move(cb).Run(); + } +} + +void SysmemCollectionClient::OnBuffersAllocated( + zx_status_t status, + fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "Failed to allocate sysmem buffers."; + OnError(status); + return; + } + + if (acquire_buffers_cb_) { + auto buffers = VmoBuffer::CreateBuffersFromSysmemCollection( + &buffer_collection_info, writable_); + std::move(acquire_buffers_cb_) + .Run(std::move(buffers), buffer_collection_info.settings); + } +} + +void SysmemCollectionClient::OnError(zx_status_t status) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ZX_DLOG(ERROR, status) << "Connection to BufferCollection was disconnected."; + collection_.Unbind(); + if (acquire_buffers_cb_) + std::move(acquire_buffers_cb_).Run({}, {}); +} + +SysmemAllocatorClient::SysmemAllocatorClient(base::StringPiece client_name) { + allocator_ = base::ComponentContextForProcess() + ->svc() + ->Connect<fuchsia::sysmem::Allocator>(); + + allocator_->SetDebugClientInfo(std::string(client_name), + base::GetCurrentProcId()); + + allocator_.set_error_handler([](zx_status_t status) { + // Just log a warning. We will handle BufferCollection the failure when + // trying to create a new BufferCollection. + ZX_DLOG(WARNING, status) + << "The fuchsia.sysmem.Allocator channel was disconnected."; + }); +} + +SysmemAllocatorClient::~SysmemAllocatorClient() = default; + +fuchsia::sysmem::BufferCollectionTokenPtr +SysmemAllocatorClient::CreateNewToken() { + fuchsia::sysmem::BufferCollectionTokenPtr collection_token; + allocator_->AllocateSharedCollection(collection_token.NewRequest()); + return collection_token; +} + +std::unique_ptr<SysmemCollectionClient> +SysmemAllocatorClient::AllocateNewCollection() { + return std::make_unique<SysmemCollectionClient>(allocator_.get(), + CreateNewToken()); +} + +std::unique_ptr<SysmemCollectionClient> +SysmemAllocatorClient::BindSharedCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token) { + return std::make_unique<SysmemCollectionClient>(allocator_.get(), + std::move(token)); +} + +} // namespace media
diff --git a/media/fuchsia/common/sysmem_client.h b/media/fuchsia/common/sysmem_client.h new file mode 100644 index 0000000..acedf70 --- /dev/null +++ b/media/fuchsia/common/sysmem_client.h
@@ -0,0 +1,110 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_ +#define MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_ + +#include <fuchsia/media/cpp/fidl.h> +#include <fuchsia/sysmem/cpp/fidl.h> + +#include <vector> + +#include "base/callback.h" +#include "base/threading/thread_checker.h" + +namespace media { + +class VmoBuffer; + +// Wrapper for fuchsia.sysmem.BufferCollection . It provides the following two +// features: +// 1. Calls Sync() and ensures that it completes before buffer constrains are +// set and shared tokens are passed to other participants. +// 2. Provides AcquireBuffers() that allows to acquire buffers and handle +// possible errors. +class SysmemCollectionClient { + public: + static constexpr uint32_t kDefaultNamePriority = 100; + + // Callback for GetSharedToken(). + using GetSharedTokenCB = + base::OnceCallback<void(fuchsia::sysmem::BufferCollectionTokenPtr token)>; + + // Callback for AcquireBuffers(). Called with an empty |buffers| if buffers + // allocation failed. + using AcquireBuffersCB = base::OnceCallback<void( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& settings)>; + + SysmemCollectionClient( + fuchsia::sysmem::Allocator* allocator, + fuchsia::sysmem::BufferCollectionTokenPtr collection_token); + ~SysmemCollectionClient(); + + SysmemCollectionClient(const SysmemCollectionClient&) = delete; + SysmemCollectionClient& operator=(const SysmemCollectionClient&) = delete; + + // Creates one shared token to be shared with other participants and returns + // it asynchronously, when it's safe to pass it (i.e. after Sync()). Must be + // called before Initialize(). + void CreateSharedToken(GetSharedTokenCB cb); + + // Initializes the collection with the given name and constraints. + void Initialize(fuchsia::sysmem::BufferCollectionConstraints constraints, + base::StringPiece name, + uint32_t name_priority = kDefaultNamePriority); + + // Create VmoBuffers to access raw memory. Should be called only after + // GetSharedToken() has been called for all shared tokens. + void AcquireBuffers(AcquireBuffersCB cb); + + private: + void OnSyncComplete(); + void OnBuffersAllocated( + zx_status_t status, + fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); + void OnError(zx_status_t status); + + fuchsia::sysmem::Allocator* const allocator_; + fuchsia::sysmem::BufferCollectionTokenPtr collection_token_; + fuchsia::sysmem::BufferCollectionPtr collection_; + + bool writable_ = false; + std::vector<base::OnceClosure> sync_completion_closures_; + AcquireBuffersCB acquire_buffers_cb_; + + THREAD_CHECKER(thread_checker_); +}; + +// Helper fuchsia.sysmem.Allocator . +class SysmemAllocatorClient { + public: + explicit SysmemAllocatorClient(base::StringPiece client_name); + ~SysmemAllocatorClient(); + + SysmemAllocatorClient(const SysmemAllocatorClient&) = delete; + SysmemAllocatorClient& operator=(const SysmemAllocatorClient&) = delete; + + fuchsia::sysmem::BufferCollectionTokenPtr CreateNewToken(); + + // Creates new buffer collection. + std::unique_ptr<SysmemCollectionClient> AllocateNewCollection(); + + // Binds the specified token to a SysmemCollectionClient. + std::unique_ptr<SysmemCollectionClient> BindSharedCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token); + + // TODO(crbug.com/1131183): Update FuchsiaVideoDecoder to use + // SysmemCollectionClient and remove this function. + fuchsia::sysmem::Allocator* raw() { return allocator_.get(); } + + private: + friend SysmemCollectionClient; + + fuchsia::sysmem::AllocatorPtr allocator_; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc index 7523178f..9603507 100644 --- a/net/http/transport_security_persister.cc +++ b/net/http/transport_security_persister.cc
@@ -361,25 +361,25 @@ return true; } -bool TransportSecurityPersister::LoadEntries(const std::string& serialized) { +void TransportSecurityPersister::LoadEntries(const std::string& serialized) { DCHECK(foreground_runner_->RunsTasksInCurrentSequence()); transport_security_state_->ClearDynamicData(); - return Deserialize(serialized, transport_security_state_); + Deserialize(serialized, transport_security_state_); } -bool TransportSecurityPersister::Deserialize(const std::string& serialized, +void TransportSecurityPersister::Deserialize(const std::string& serialized, TransportSecurityState* state) { absl::optional<base::Value> value = base::JSONReader::Read(serialized); if (!value || !value->is_dict()) - return false; + return; absl::optional<int> version = value->FindIntKey(kVersionKey); // Stop if the data is out of date (or in the previous format that didn't have // a version number). if (!version || *version != kCurrentVersionValue) - return false; + return; base::Value* sts_value = value->FindKey(kSTSKey); if (sts_value) @@ -392,7 +392,6 @@ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ExpectCT.EntriesOnLoad", state->num_expect_ct_entries(), 1 /* min */, 2000 /* max */, 40 /* buckets */); - return true; } void TransportSecurityPersister::CompleteLoad(const std::string& state) {
diff --git a/net/http/transport_security_persister.h b/net/http/transport_security_persister.h index 71b27ed9..aa30cbbe 100644 --- a/net/http/transport_security_persister.h +++ b/net/http/transport_security_persister.h
@@ -106,12 +106,11 @@ // Clears any existing non-static entries, and then re-populates // |transport_security_state_|. - bool LoadEntries(const std::string& serialized); + void LoadEntries(const std::string& serialized); private: - // Populates |state| from the JSON string |serialized|. Returns true if - // all entries were parsed and deserialized correctly. - static bool Deserialize(const std::string& serialized, + // Populates |state| from the JSON string |serialized|. + static void Deserialize(const std::string& serialized, TransportSecurityState* state); void CompleteLoad(const std::string& state);
diff --git a/net/http/transport_security_persister_unittest.cc b/net/http/transport_security_persister_unittest.cc index 03cd04f5..530e98ff 100644 --- a/net/http/transport_security_persister_unittest.cc +++ b/net/http/transport_security_persister_unittest.cc
@@ -105,18 +105,24 @@ EXPECT_TRUE(state_->GetDynamicExpectCTState( kYahooDomain, NetworkIsolationKey(), &expect_ct_state)); - EXPECT_TRUE(persister_->LoadEntries("{\"version\":2}")); + persister_->LoadEntries("{\"version\":2}"); EXPECT_FALSE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); EXPECT_FALSE(state_->GetDynamicExpectCTState( kYahooDomain, NetworkIsolationKey(), &expect_ct_state)); } +// Tests that serializing -> deserializing -> reserializing results in the same +// output. TEST_P(TransportSecurityPersisterTest, SerializeData1) { std::string output; EXPECT_TRUE(persister_->SerializeData(&output)); - EXPECT_TRUE(persister_->LoadEntries(output)); + persister_->LoadEntries(output); + + std::string output2; + EXPECT_TRUE(persister_->SerializeData(&output2)); + EXPECT_EQ(output, output2); } TEST_P(TransportSecurityPersisterTest, SerializeData2) { @@ -132,7 +138,7 @@ std::string output; EXPECT_TRUE(persister_->SerializeData(&output)); - EXPECT_TRUE(persister_->LoadEntries(output)); + persister_->LoadEntries(output); EXPECT_TRUE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, @@ -196,7 +202,7 @@ std::string persisted; EXPECT_TRUE(base::ReadFileToString(path, &persisted)); EXPECT_EQ(persisted, serialized); - EXPECT_TRUE(persister_->LoadEntries(persisted)); + persister_->LoadEntries(persisted); // Check that states are the same as saved. size_t count = 0; @@ -216,12 +222,28 @@ EXPECT_EQ(count, expect_ct_saved.size()); } +// Tests that deserializing bad data shouldn't result in any ExpectCT or STS +// entries being added to the transport security state. TEST_P(TransportSecurityPersisterTest, DeserializeBadData) { - EXPECT_FALSE(persister_->LoadEntries("")); - EXPECT_FALSE(persister_->LoadEntries("Foopy")); - EXPECT_FALSE(persister_->LoadEntries("15")); - EXPECT_FALSE(persister_->LoadEntries("[15]")); - EXPECT_FALSE(persister_->LoadEntries("{\"version\":1}")); + persister_->LoadEntries(""); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); + + persister_->LoadEntries("Foopy"); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); + + persister_->LoadEntries("15"); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); + + persister_->LoadEntries("[15]"); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); + + persister_->LoadEntries("{\"version\":1}"); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); } TEST_P(TransportSecurityPersisterTest, DeserializeDataOldWithoutCreationDate) { @@ -235,7 +257,9 @@ "\"mode\": \"strict\" " "}" "}"; - EXPECT_FALSE(persister_->LoadEntries(kInput)); + persister_->LoadEntries(kInput); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); } TEST_P(TransportSecurityPersisterTest, DeserializeDataOldMergedDictionary) { @@ -275,7 +299,9 @@ " }" "}"; - EXPECT_FALSE(persister_->LoadEntries(kInput)); + persister_->LoadEntries(kInput); + EXPECT_EQ(0u, state_->num_expect_ct_entries()); + EXPECT_EQ(0u, state_->num_sts_entries()); } // Tests that dynamic Expect-CT state is serialized and deserialized correctly. @@ -298,7 +324,7 @@ EXPECT_TRUE(persister_->SerializeData(&serialized)); // LoadEntries() clears existing dynamic data before loading entries from // |serialized|. - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); TransportSecurityState::ExpectCTState new_expect_ct_state; EXPECT_TRUE(state_->GetDynamicExpectCTState( @@ -312,7 +338,7 @@ state_->AddExpectCT(kTestDomain, expiry, false /* enforce */, report_uri, NetworkIsolationKey()); EXPECT_TRUE(persister_->SerializeData(&serialized)); - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); EXPECT_TRUE(state_->GetDynamicExpectCTState( kTestDomain, NetworkIsolationKey(), &new_expect_ct_state)); EXPECT_FALSE(new_expect_ct_state.enforce); @@ -343,7 +369,7 @@ EXPECT_TRUE(persister_->SerializeData(&serialized)); // LoadEntries() clears existing dynamic data before loading entries from // |serialized|. - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); TransportSecurityState::ExpectCTState new_expect_ct_state; EXPECT_TRUE(state_->GetDynamicExpectCTState( @@ -377,7 +403,7 @@ NetworkIsolationKey()); std::string serialized; EXPECT_TRUE(persister_->SerializeData(&serialized)); - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); TransportSecurityState::ExpectCTState new_expect_ct_state; EXPECT_FALSE(state_->GetDynamicExpectCTState( @@ -437,7 +463,7 @@ } // Load entries into the other persister. - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); if (partition_expect_ct_state()) { TransportSecurityState::ExpectCTState new_expect_ct_state; @@ -521,7 +547,7 @@ "\"Not a valid NIK\""); // Load entries into the other persister. - EXPECT_TRUE(persister_->LoadEntries(serialized)); + persister_->LoadEntries(serialized); // The entry with the non-empty NetworkIsolationKey should be dropped, since // its NIK is now invalid. The other entry should be preserved.
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc index c736aef8..857a7b4d 100644 --- a/net/http/transport_security_state.cc +++ b/net/http/transport_security_state.cc
@@ -1072,6 +1072,10 @@ return enabled_expect_ct_hosts_.size(); } +size_t TransportSecurityState::num_sts_entries() const { + return enabled_sts_hosts_.size(); +} + // static bool TransportSecurityState::IsBuildTimely() { const base::Time build_time = base::GetBuildTime();
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h index 94b1ffc..aa1c837 100644 --- a/net/http/transport_security_state.h +++ b/net/http/transport_security_state.h
@@ -576,6 +576,9 @@ // The number of cached ExpectCTState entries. size_t num_expect_ct_entries() const; + // The number of cached STSState entries. + size_t num_sts_entries() const; + private: friend class TransportSecurityStateTest; friend class TransportSecurityStateStaticFuzzer;
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc index 20f31aa..dc0baf895 100644 --- a/printing/backend/print_backend_cups.cc +++ b/printing/backend/print_backend_cups.cc
@@ -81,7 +81,7 @@ const char* drv_info = cupsGetOption(kCUPSOptPrinterMakeAndModel, printer.num_options, printer.options); if (drv_info) - printer_info->options[kDriverInfoTagName] = *drv_info; + printer_info->options[kDriverInfoTagName] = drv_info; // Store printer options. for (int opt_index = 0; opt_index < printer.num_options; ++opt_index) {
diff --git a/printing/backend/print_backend_cups_unittest.cc b/printing/backend/print_backend_cups_unittest.cc index e7b4318..39ac7fc 100644 --- a/printing/backend/print_backend_cups_unittest.cc +++ b/printing/backend/print_backend_cups_unittest.cc
@@ -81,6 +81,17 @@ EXPECT_EQ(kName, printer_info.display_name); #endif EXPECT_EQ(kDescription, printer_info.printer_description); + + // The option value of `kCUPSOptPrinterMakeAndModel` is used to set the value + // for `kDriverInfoTagName`. + auto driver = printer_info.options.find(kDriverInfoTagName); +#if defined(OS_MAC) + ASSERT_NE(driver, printer_info.options.end()); + EXPECT_EQ(kDescription, driver->second); +#else + // Didn't set option for `kCUPSOptPrinterMakeAndModel`. + EXPECT_EQ(driver, printer_info.options.end()); +#endif } TEST(PrintBackendCupsTest, PrinterDriverInfoFromCUPS) {
diff --git a/remoting/host/installer/linux/BUILD.gn b/remoting/host/installer/linux/BUILD.gn index 22ab53a..638f381 100644 --- a/remoting/host/installer/linux/BUILD.gn +++ b/remoting/host/installer/linux/BUILD.gn
@@ -53,7 +53,9 @@ "debian/control", "debian/copyright", "debian/postinst", + "debian/postrm", "debian/preinst", + "debian/prerm", "debian/rules", "debian/triggers", ]
diff --git a/remoting/host/installer/linux/debian/prerm b/remoting/host/installer/linux/debian/prerm new file mode 100755 index 0000000..d116fec2 --- /dev/null +++ b/remoting/host/installer/linux/debian/prerm
@@ -0,0 +1,15 @@ +#!/bin/bash + +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e + +if [ "$1" = "remove" ]; then + # Stop the service when the package is being removed. + echo "Stopping Chrome Remote Desktop service..." + systemctl stop 'chrome-remote-desktop@*' +fi + +#DEBHELPER#
diff --git a/remoting/host/linux/linux_me2me_host.py b/remoting/host/linux/linux_me2me_host.py index 024b82a7..1800ced 100755 --- a/remoting/host/linux/linux_me2me_host.py +++ b/remoting/host/linux/linux_me2me_host.py
@@ -95,6 +95,8 @@ USER_SESSION_PATH = os.path.join(SCRIPT_DIR, "user-session") +SETUP_URL_FORWARDER_PATH = os.path.join(SCRIPT_DIR, "setup-url-forwarder") + CHROME_REMOTING_GROUP_NAME = "chrome-remote-desktop" HOME_DIR = os.environ["HOME"] @@ -825,6 +827,21 @@ finally: self.host_proc.stdin.close() + def restore_default_browser(self): + # Restores the previous default browser settings in case the host crashes + # during a remote session. It's noop if the current default browser is not + # the CRD URL forwarder. + + if not os.path.exists(SETUP_URL_FORWARDER_PATH): + print('Cannot find the URL forwarder setup script', file=sys.stderr) + return + print('Attempting to restore previous default browser...') + retcode = subprocess.call([SETUP_URL_FORWARDER_PATH, "--restore"], + env=self.child_env) + if retcode != 0: + print('URL forwarder setup script returned a non-zero code:', retcode, + file=sys.stderr) + def shutdown_all_procs(self): """Send SIGTERM to all procs and wait for them to exit. Will fallback to SIGKILL if a process doesn't exit within 10 seconds. @@ -1284,6 +1301,7 @@ global g_desktop if g_desktop is not None: + g_desktop.restore_default_browser() g_desktop.shutdown_all_procs() if g_desktop.xorg_conf is not None: os.remove(g_desktop.xorg_conf) @@ -1834,6 +1852,11 @@ if desktop.host_proc is None: logging.info("Launching host process") + # Restore the previous default browser in case the daemon script has + # crashed or the system has been rebooted in the middle of a remote + # session. + desktop.restore_default_browser() + extra_start_host_args = [] if HOST_EXTRA_PARAMS_ENV_VAR in os.environ: extra_start_host_args = \
diff --git a/sandbox/policy/mac/BUILD.gn b/sandbox/policy/mac/BUILD.gn index 79c930e5..984fca8 100644 --- a/sandbox/policy/mac/BUILD.gn +++ b/sandbox/policy/mac/BUILD.gn
@@ -9,6 +9,7 @@ "cdm.sb", "common.sb", "gpu.sb", + "mirroring.sb", "nacl_loader.sb", "network.sb", "ppapi.sb",
diff --git a/sandbox/policy/mac/mirroring.sb b/sandbox/policy/mac/mirroring.sb new file mode 100644 index 0000000..0b7794b --- /dev/null +++ b/sandbox/policy/mac/mirroring.sb
@@ -0,0 +1,11 @@ +; Copyright 2021 The Chromium Authors. All rights reserved. +; Use of this source code is governed by a BSD-style license that can be +; found in the LICENSE file. + +; --- The contents of common.sb implicitly included here. --- + +; Needed for IOSurface GpuMemoryBuffer video frame access +; https://crbug.com/1204603 +(allow iokit-open + (iokit-registry-entry-class "IOSurfaceRootUserClient") +)
diff --git a/sandbox/policy/mac/sandbox_mac.mm b/sandbox/policy/mac/sandbox_mac.mm index db147c48..c660515 100644 --- a/sandbox/policy/mac/sandbox_mac.mm +++ b/sandbox/policy/mac/sandbox_mac.mm
@@ -16,6 +16,7 @@ #include "sandbox/policy/mac/cdm.sb.h" #include "sandbox/policy/mac/common.sb.h" #include "sandbox/policy/mac/gpu.sb.h" +#include "sandbox/policy/mac/mirroring.sb.h" #include "sandbox/policy/mac/nacl_loader.sb.h" #include "sandbox/policy/mac/network.sb.h" #include "sandbox/policy/mac/ppapi.sb.h" @@ -57,6 +58,9 @@ case SandboxType::kGpu: profile += kSeatbeltPolicyString_gpu; break; + case SandboxType::kMirroring: + profile += kSeatbeltPolicyString_mirroring; + break; case SandboxType::kNaClLoader: profile += kSeatbeltPolicyString_nacl_loader; break;
diff --git a/sandbox/policy/sandbox_type.cc b/sandbox/policy/sandbox_type.cc index 870a6c6..21b207ca3 100644 --- a/sandbox/policy/sandbox_type.cc +++ b/sandbox/policy/sandbox_type.cc
@@ -53,6 +53,7 @@ #endif case SandboxType::kPrintCompositor: #if defined(OS_MAC) + case SandboxType::kMirroring: case SandboxType::kNaClLoader: #endif #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -133,6 +134,9 @@ case SandboxType::kLibassistant: #endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX) #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_MAC) + case SandboxType::kMirroring: +#endif // defined(OS_MAC) #if !defined(OS_MAC) case SandboxType::kService: #endif @@ -258,6 +262,10 @@ case SandboxType::kMediaFoundationCdm: return switches::kMediaFoundationCdmSandbox; #endif // defined(OS_WIN) +#if defined(OS_MAC) + case SandboxType::kMirroring: + return switches::kMirroringSandbox; +#endif #if BUILDFLAG(IS_CHROMEOS_ASH) case SandboxType::kIme: return switches::kImeSandbox; @@ -319,6 +327,10 @@ if (sandbox_string == switches::kMediaFoundationCdmSandbox) return SandboxType::kMediaFoundationCdm; #endif +#if defined(OS_MAC) + if (sandbox_string == switches::kMirroringSandbox) + return SandboxType::kMirroring; +#endif if (sandbox_string == switches::kAudioSandbox) return SandboxType::kAudio; if (sandbox_string == switches::kSpeechRecognitionSandbox)
diff --git a/sandbox/policy/sandbox_type.h b/sandbox/policy/sandbox_type.h index 14f1695..88903f7 100644 --- a/sandbox/policy/sandbox_type.h +++ b/sandbox/policy/sandbox_type.h
@@ -76,6 +76,9 @@ #if defined(OS_MAC) // The NaCl loader process. kNaClLoader, + + // The mirroring service needs IOSurface access on macOS. + kMirroring, #endif // defined(OS_MAC) #if BUILDFLAG(ENABLE_PRINTING)
diff --git a/sandbox/policy/switches.cc b/sandbox/policy/switches.cc index 4862627..c0438f6 100644 --- a/sandbox/policy/switches.cc +++ b/sandbox/policy/switches.cc
@@ -46,6 +46,10 @@ const char kMediaFoundationCdmSandbox[] = "mf_cdm"; #endif // OS_WIN +#if defined(OS_MAC) +const char kMirroringSandbox[] = "mirroring"; +#endif // OS_MAC + #if BUILDFLAG(IS_CHROMEOS_ASH) const char kImeSandbox[] = "ime"; const char kTtsSandbox[] = "tts";
diff --git a/sandbox/policy/switches.h b/sandbox/policy/switches.h index 6754f7c..a0315cd 100644 --- a/sandbox/policy/switches.h +++ b/sandbox/policy/switches.h
@@ -47,6 +47,10 @@ SANDBOX_POLICY_EXPORT extern const char kMediaFoundationCdmSandbox[]; #endif // OS_WIN +#if defined(OS_MAC) +SANDBOX_POLICY_EXPORT extern const char kMirroringSandbox[]; +#endif // OS_MAC + #if BUILDFLAG(IS_CHROMEOS_ASH) SANDBOX_POLICY_EXPORT extern const char kImeSandbox[]; SANDBOX_POLICY_EXPORT extern const char kTtsSandbox[];
diff --git a/sandbox/policy/win/sandbox_win_unittest.cc b/sandbox/policy/win/sandbox_win_unittest.cc index 591653a..44a6ea7 100644 --- a/sandbox/policy/win/sandbox_win_unittest.cc +++ b/sandbox/policy/win/sandbox_win_unittest.cc
@@ -328,7 +328,8 @@ CheckCapabilities(profile.get(), {L"cap1", L"cap2"}); } -TEST_F(SandboxWinTest, BlocklistAddOneDllCheckInBrowser) { +// Disabled due to crbug.com/1210614 +TEST_F(SandboxWinTest, DISABLED_BlocklistAddOneDllCheckInBrowser) { { // Block loaded module. TestTargetPolicy policy; BlocklistAddOneDllForTesting(L"kernel32.dll", true, &policy);
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index 12f5fc26..70774c7 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -2812,6 +2812,37 @@ } ] }, + "lacros-arm-generic-chrome": { + "additional_compile_targets": [ + "chrome", + "lacros_version_metadata", + "linux_symbols", + "symupload", + "strip_chrome_binary" + ], + "isolated_scripts": [ + { + "isolate_name": "chrome_sizes", + "merge": { + "script": "//tools/perf/process_perf_results.py" + }, + "name": "chrome_sizes", + "resultdb": { + "enable": false + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "pool": "chrome.tests" + } + ], + "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://chrome/test:chrome_sizes/" + } + ] + }, "linux-chrome": { "additional_compile_targets": [ "chrome",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 0a87d9d..d4aea48 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1736,36 +1736,100 @@ "android-backuprefptr-arm-fyi-rel": { "gtest_tests": [ { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "absl_hardening_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "absl_hardening_tests", "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_browsertests", @@ -1773,38 +1837,100 @@ }, { "args": [ - "--test-launcher-batch-limit=1" + "--test-launcher-batch-limit=1", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_sync_integration_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_sync_integration_tests", "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_webview_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_webview_unittests", @@ -1812,16 +1938,30 @@ }, { "args": [ - "angle_unittests" + "angle_unittests", + "-v" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } @@ -1833,163 +1973,452 @@ "use_isolated_scripts_api": true }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "base_unittests", "test_id_prefix": "ninja://base:base_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "base_util_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "base_util_unittests", "test_id_prefix": "ninja://base/util:base_util_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_common_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_common_unittests", "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_heap_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_heap_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_platform_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_platform_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webkit_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "name": "webkit_unit_tests", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "blink_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_crypto_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "boringssl_crypto_tests", "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_ssl_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "boringssl_ssl_tests", "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "breakpad_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "breakpad_unittests", @@ -1997,74 +2426,200 @@ }, { "args": [ - "--gtest_filter=-*UsingRealWebcam*" + "--gtest_filter=-*UsingRealWebcam*", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "capture_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "capture_unittests", "test_id_prefix": "ninja://media/capture:capture_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cast_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "cast_unittests", "test_id_prefix": "ninja://media/cast:cast_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cc_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "cc_unittests", "test_id_prefix": "ninja://cc:cc_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_smoke_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "chrome_public_smoke_test", @@ -2072,11 +2627,18 @@ }, { "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", "--git-revision=${got_revision}" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "precommit_args": [ "--gerrit-issue=${patch_issue}", @@ -2088,12 +2650,32 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, @@ -2103,20 +2685,50 @@ { "args": [ "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" + "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_vr_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, @@ -2124,73 +2736,202 @@ "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "components_unittests", "test_id_prefix": "ninja://components:components_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 + "shards": 9 }, "test": "content_browsertests", "test_id_prefix": "ninja://content/test:content_browsertests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_shell_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 }, @@ -2198,162 +2939,451 @@ "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 }, "test": "content_unittests", "test_id_prefix": "ninja://content/test:content_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crashpad_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "crashpad_tests", "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crypto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "crypto_unittests", "test_id_prefix": "ninja://crypto:crypto_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "device_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "device_unittests", "test_id_prefix": "ninja://device:device_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "display_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "display_unittests", "test_id_prefix": "ninja://ui/display:display_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "events_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "events_unittests", "test_id_prefix": "ninja://ui/events:events_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gcm_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gcm_unit_tests", "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gfx_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gfx_unittests", "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gin_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gin_unittests", @@ -2361,597 +3391,1653 @@ }, { "args": [ - "--use-cmd-decoder=validating" + "--use-cmd-decoder=validating", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_tests_validating" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "name": "gl_tests_validating", + "resultdb": { + "enable": true + }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gl_tests", "test_id_prefix": "ninja://gpu:gl_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gl_unittests", "test_id_prefix": "ninja://ui/gl:gl_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "google_apis_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "google_apis_unittests", "test_id_prefix": "ninja://google_apis:google_apis_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gpu_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gpu_unittests", "test_id_prefix": "ninja://gpu:gpu_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gwp_asan_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gwp_asan_unittests", "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ipc_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ipc_tests", "test_id_prefix": "ninja://ipc:ipc_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "jingle_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "jingle_unittests", "test_id_prefix": "ninja://jingle:jingle_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "latency_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "latency_unittests", "test_id_prefix": "ninja://ui/latency:latency_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "libjingle_xmpp_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "libjingle_xmpp_unittests", "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "liburlpattern_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "liburlpattern_unittests", "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "media_blink_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "media_blink_unittests", "test_id_prefix": "ninja://media/blink:media_blink_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "media_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "media_unittests", "test_id_prefix": "ninja://media:media_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "midi_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "midi_unittests", "test_id_prefix": "ninja://media/midi:midi_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "mojo_test_apk", "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "mojo_unittests", "test_id_prefix": "ninja://mojo:mojo_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "net_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 }, "test": "net_unittests", "test_id_prefix": "ninja://net:net_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "perfetto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "perfetto_unittests", "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sandbox_linux_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sandbox_linux_unittests", "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "services_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "services_unittests", "test_id_prefix": "ninja://services:services_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "shell_dialogs_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "shell_dialogs_unittests", "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "skia_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "skia_unittests", "test_id_prefix": "ninja://skia:skia_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sql_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sql_unittests", "test_id_prefix": "ninja://sql:sql_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "storage_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "storage_unittests", "test_id_prefix": "ninja://storage:storage_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_android_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_android_unittests", "test_id_prefix": "ninja://ui/android:ui_android_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_base_unittests", "test_id_prefix": "ninja://ui/base:ui_base_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_touch_selection_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_touch_selection_unittests", "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "url_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "url_unittests", "test_id_prefix": "ninja://url:url_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "viz_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "viz_unittests", "test_id_prefix": "ninja://components/viz:viz_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_android_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_android_unittests", "test_id_prefix": "ninja://chrome/browser/android/vr:vr_android_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_common_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_common_unittests", "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_pixeltests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_pixeltests", "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 7 }, @@ -2959,36 +5045,100 @@ "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "wtf_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "wtf_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "zlib_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "zlib_unittests", @@ -2999,42 +5149,100 @@ "android-backuprefptr-arm64-fyi-rel": { "gtest_tests": [ { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "absl_hardening_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "absl_hardening_tests", "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_browsertests", @@ -3042,44 +5250,100 @@ }, { "args": [ - "--test-launcher-batch-limit=1" + "--test-launcher-batch-limit=1", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_sync_integration_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_sync_integration_tests", "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_webview_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "android_webview_unittests", @@ -3087,7 +5351,8 @@ }, { "args": [ - "angle_unittests" + "angle_unittests", + "-v" ], "merge": { "args": [], @@ -3098,8 +5363,18 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } @@ -3111,114 +5386,268 @@ "use_isolated_scripts_api": true }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "base_unittests", "test_id_prefix": "ninja://base:base_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "base_util_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "base_util_unittests", "test_id_prefix": "ninja://base/util:base_util_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_common_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_common_unittests", "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_heap_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_heap_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_platform_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "blink_platform_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webkit_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "name": "webkit_unit_tests", "resultdb": { @@ -3226,75 +5655,183 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "blink_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_crypto_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "boringssl_crypto_tests", "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_ssl_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "boringssl_ssl_tests", "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "breakpad_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "breakpad_unittests", @@ -3302,86 +5839,200 @@ }, { "args": [ - "--gtest_filter=-*UsingRealWebcam*" + "--gtest_filter=-*UsingRealWebcam*", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "capture_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "capture_unittests", "test_id_prefix": "ninja://media/capture:capture_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cast_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "cast_unittests", "test_id_prefix": "ninja://media/cast:cast_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cc_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "cc_unittests", "test_id_prefix": "ninja://cc:cc_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_smoke_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "chrome_public_smoke_test", @@ -3389,11 +6040,18 @@ }, { "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", "--git-revision=${got_revision}" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "precommit_args": [ "--gerrit-issue=${patch_issue}", @@ -3405,12 +6063,32 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, @@ -3420,23 +6098,50 @@ { "args": [ "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" + "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_vr_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 2 }, @@ -3444,85 +6149,202 @@ "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "components_unittests", "test_id_prefix": "ninja://components:components_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 + "shards": 9 }, "test": "content_browsertests", "test_id_prefix": "ninja://content/test:content_browsertests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_shell_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 3 }, @@ -3530,189 +6352,451 @@ "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 }, "test": "content_unittests", "test_id_prefix": "ninja://content/test:content_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crashpad_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "crashpad_tests", "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crypto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "crypto_unittests", "test_id_prefix": "ninja://crypto:crypto_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "device_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "device_unittests", "test_id_prefix": "ninja://device:device_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "display_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "display_unittests", "test_id_prefix": "ninja://ui/display:display_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "events_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "events_unittests", "test_id_prefix": "ninja://ui/events:events_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gcm_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gcm_unit_tests", "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gfx_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gfx_unittests", "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gin_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gin_unittests", @@ -3720,11 +6804,18 @@ }, { "args": [ - "--use-cmd-decoder=validating" + "--use-cmd-decoder=validating", + "--gs-results-bucket=chromium-result-details", + "--recover-devices" ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_tests_validating" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "name": "gl_tests_validating", "resultdb": { @@ -3732,684 +6823,1634 @@ }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gl_tests", "test_id_prefix": "ninja://gpu:gl_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gl_unittests", "test_id_prefix": "ninja://ui/gl:gl_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "google_apis_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "google_apis_unittests", "test_id_prefix": "ninja://google_apis:google_apis_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gpu_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gpu_unittests", "test_id_prefix": "ninja://gpu:gpu_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gwp_asan_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "gwp_asan_unittests", "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ipc_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ipc_tests", "test_id_prefix": "ninja://ipc:ipc_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "jingle_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "jingle_unittests", "test_id_prefix": "ninja://jingle:jingle_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "latency_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "latency_unittests", "test_id_prefix": "ninja://ui/latency:latency_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "libjingle_xmpp_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "libjingle_xmpp_unittests", "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "liburlpattern_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "liburlpattern_unittests", "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "media_blink_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "media_blink_unittests", "test_id_prefix": "ninja://media/blink:media_blink_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "media_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "media_unittests", "test_id_prefix": "ninja://media:media_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "midi_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "midi_unittests", "test_id_prefix": "ninja://media/midi:midi_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "mojo_test_apk", "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "mojo_unittests", "test_id_prefix": "ninja://mojo:mojo_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "net_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 }, "test": "net_unittests", "test_id_prefix": "ninja://net:net_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "perfetto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "perfetto_unittests", "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sandbox_linux_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sandbox_linux_unittests", "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "services_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "services_unittests", "test_id_prefix": "ninja://services:services_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "shell_dialogs_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "shell_dialogs_unittests", "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "skia_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "skia_unittests", "test_id_prefix": "ninja://skia:skia_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sql_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "sql_unittests", "test_id_prefix": "ninja://sql:sql_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "storage_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "storage_unittests", "test_id_prefix": "ninja://storage:storage_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_android_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_android_unittests", "test_id_prefix": "ninja://ui/android:ui_android_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_base_unittests", "test_id_prefix": "ninja://ui/base:ui_base_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_touch_selection_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "ui_touch_selection_unittests", "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "url_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "url_unittests", "test_id_prefix": "ninja://url:url_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "viz_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "viz_unittests", "test_id_prefix": "ninja://components/viz:viz_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_android_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_android_unittests", "test_id_prefix": "ninja://chrome/browser/android/vr:vr_android_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_common_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_common_unittests", "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "vr_pixeltests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "vr_pixeltests", "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 7 }, @@ -4417,42 +8458,100 @@ "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "wtf_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "wtf_unittests", "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" }, { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "zlib_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, "resultdb": { "enable": true }, "swarming": { "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], "dimension_sets": [ { + "device_os": "PQ3A.190801.002", + "device_os_flavor": "google", + "device_os_type": "userdebug", "device_type": "walleye", "os": "Android" } ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test": "zlib_unittests",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index a476a7e..f25f15e3 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -145,6 +145,22 @@ }, 'os_type': 'chromeos', }, + 'lacros-arm-generic-chrome': { + 'additional_compile_targets': [ + 'chrome', + 'lacros_version_metadata', + 'linux_symbols', + 'symupload', + 'strip_chrome_binary' + ], + 'mixins': [ + 'chrome-swarming-pool', + ], + 'test_suites': { + 'isolated_scripts': 'chrome_sizes', + }, + 'os_type': 'chromeos', + }, 'linux-chrome': { 'additional_compile_targets': [ 'chrome', @@ -2689,8 +2705,11 @@ 'gtest_tests': 'chromium_android_gtests', }, 'mixins': [ + 'enable_resultdb', + 'pie_fleet', 'walleye', ], + 'os_type': 'android', }, 'android-backuprefptr-arm64-fyi-rel': { 'test_suites': { @@ -2698,8 +2717,10 @@ }, 'mixins': [ 'enable_resultdb', + 'pie_fleet', 'walleye', ], + 'os_type': 'android', }, 'android-code-coverage': { 'mixins': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 58c4cc7..6176d48e 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4140,10 +4140,11 @@ { "name": "G2_20201202", "params": { - "BlockedTypes": "28", - "Gen": "2", - "Max": "10", - "Rho": "100" + "BlockedHashes": "44033, 44289, 286465, 680961, 681473, 693249, 693505,693761, 694017, 696065, 880129, 881409, 881665, 881921", + "BlockedTypes": "13, 25, 28", + "Gen": "5", + "Max": "40", + "Rho": "19" }, "enable_features": [ "IdentifiabilityStudy" @@ -5722,22 +5723,6 @@ ] } ], - "PageInfoV2": [ - { - "platforms": [ - "android", - "android_weblayer" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "PageInfoV2" - ] - } - ] - } - ], "PageLoadMetricsBufferTimer": [ { "platforms": [
diff --git a/testing/xvfb.py b/testing/xvfb.py index 05acea14..699cc42 100755 --- a/testing/xvfb.py +++ b/testing/xvfb.py
@@ -97,9 +97,8 @@ Args: cmd: Command to be executed. - env: A copy of environment variables, "DISPLAY" and - "_CHROMIUM_INSIDE_XVFB" will be set if Xvfb is used. "WAYLAND_DISPLAY" - will be set if Weston is used. + env: A copy of environment variables. "DISPLAY" and will be set if Xvfb is + used. "WAYLAND_DISPLAY" will be set if Weston is used. stdoutfile: If provided, symbolization via script is disabled and stdout is written to this file as well as to stdout. use_openbox: A flag to use openbox process. @@ -141,7 +140,6 @@ def _run_with_xvfb(cmd, env, stdoutfile, use_openbox, use_xcompmgr): - env['_CHROMIUM_INSIDE_XVFB'] = '1' openbox_proc = None xcompmgr_proc = None xvfb_proc = None
diff --git a/testing/xvfb_test_script.py b/testing/xvfb_test_script.py index e1dcdae..8a5b17cd 100755 --- a/testing/xvfb_test_script.py +++ b/testing/xvfb_test_script.py
@@ -23,9 +23,6 @@ signal.signal(signal.SIGTERM, print_signal) signal.signal(signal.SIGINT, print_signal) - # test if inside xvfb flag is set. - print 'Inside_xvfb :{}'.format( - os.environ.get('_CHROMIUM_INSIDE_XVFB', 'None')) # test the subprocess display number. print 'Display :{}'.format(os.environ.get('DISPLAY', 'None'))
diff --git a/testing/xvfb_unittest.py b/testing/xvfb_unittest.py index b84196f4..f28b6d2 100755 --- a/testing/xvfb_unittest.py +++ b/testing/xvfb_unittest.py
@@ -66,14 +66,10 @@ def test_no_xvfb_flag(self): proc = launch_process(['--no-xvfb']) proc.wait() - environ_flag = read_subprocess_message(proc, 'Inside_xvfb :') - self.assertEqual(environ_flag, 'None') def test_xvfb_flag(self): proc = launch_process([]) proc.wait() - environ_flag = read_subprocess_message(proc, 'Inside_xvfb :') - self.assertEqual(environ_flag, '1') def test_xvfb_race_condition(self): proc_list = [launch_process([]) for _ in range(15)]
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 9e96a9b..058bdab 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -345,6 +345,10 @@ const base::Feature kFontAccessPersistent{"FontAccessPersistent", base::FEATURE_DISABLED_BY_DEFAULT}; +// Kill switch for the Compute Pressure API. https://crbug.com/1067627 +const base::Feature kComputePressure{"ComputePressure", + base::FEATURE_ENABLED_BY_DEFAULT}; + // Prefetch request properties are updated to be privacy-preserving. See // crbug.com/988956. const base::Feature kPrefetchPrivacyChanges{"PrefetchPrivacyChanges", @@ -939,7 +943,7 @@ // have their rendering throttled on display:none or zero-area. const base::Feature kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes{ "ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Kill switch for the Fledge Interest Group API, i.e. if disabled, the // API exposure will be disabled regardless of the OT config.
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 3556584..e9fa9d8 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -97,6 +97,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kTextFragmentAnchor; BLINK_COMMON_EXPORT extern const base::Feature kFontAccess; BLINK_COMMON_EXPORT extern const base::Feature kFontAccessPersistent; +BLINK_COMMON_EXPORT extern const base::Feature kComputePressure; BLINK_COMMON_EXPORT extern const base::Feature kFileHandlingAPI; BLINK_COMMON_EXPORT extern const base::Feature kAllowSyncXHRInPageDismissal; BLINK_COMMON_EXPORT extern const base::Feature kPrefetchPrivacyChanges;
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index c049c77..b55e897 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6499,6 +6499,7 @@ usb vertical-scroll web-share + window-placement xr-spatial-tracking # Reason for a permissions policy feature to be disabled.
diff --git a/third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom b/third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom index 5695984..41de86e 100644 --- a/third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom +++ b/third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom
@@ -141,6 +141,9 @@ // Client Hint for the preferred color scheme. kClientHintPrefersColorScheme = 85, + // Controls use of Multi-Screen Window Placement API. + kWindowPlacement = 86, + // Don't change assigned numbers of any item, and don't reuse removed slots. // Add new features at the end of the enum. // Also, run update_permissions_policy_enum.py in
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc index 504d551..37c1b9a 100644 --- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc +++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -381,7 +381,7 @@ // If a keypress event is prevented, the cursor position may be out of // sync as RenderWidgetHostViewCocoa::insertText assumes that the text // has been accepted. See https://crbug.com/1204523 for details. - if (event_->type() == event_type_names::kKeypress) + if (event_->type() == event_type_names::kKeypress && view_) view_->GetFrame().GetEditor().SyncSelection(SyncCondition::kForced); #endif // defined(OS_MAC) }
diff --git a/third_party/blink/renderer/core/html/forms/base_button_input_type.cc b/third_party/blink/renderer/core/html/forms/base_button_input_type.cc index fface02..cf415b2 100644 --- a/third_party/blink/renderer/core/html/forms/base_button_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/base_button_input_type.cc
@@ -77,7 +77,7 @@ LayoutObject* BaseButtonInputType::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateButton(GetElement(), style, legacy); + return LayoutObjectFactory::CreateButton(GetElement(), legacy); } InputType::ValueMode BaseButtonInputType::GetValueMode() const {
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc index 3b04500..121aa25 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -209,8 +209,7 @@ LayoutObject* FileInputType::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateFileUploadControl(GetElement(), style, - legacy); + return LayoutObjectFactory::CreateFileUploadControl(GetElement(), legacy); } InputType::ValueMode FileInputType::GetValueMode() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_button_element.cc b/third_party/blink/renderer/core/html/forms/html_button_element.cc index 5b52558..3d178fb 100644 --- a/third_party/blink/renderer/core/html/forms/html_button_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -57,7 +57,7 @@ display == EDisplay::kInlineLayoutCustom || display == EDisplay::kLayoutCustom) return HTMLFormControlElement::CreateLayoutObject(style, legacy); - return LayoutObjectFactory::CreateButton(*this, style, legacy); + return LayoutObjectFactory::CreateButton(*this, legacy); } const AtomicString& HTMLButtonElement::FormControlType() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc index 93ab4d0..bf9a257 100644 --- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -121,7 +121,7 @@ LayoutObject* HTMLFieldSetElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateFieldset(*this, style, legacy); + return LayoutObjectFactory::CreateFieldset(*this, legacy); } LayoutBox* HTMLFieldSetElement::GetLayoutBoxForScrolling() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc index 88e95ee..cbc847f8 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -406,7 +406,7 @@ const ComputedStyle& style, LegacyLayout legacy_layout) { if (UsesMenuList()) - return LayoutObjectFactory::CreateFlexibleBox(*this, style, legacy_layout); + return LayoutObjectFactory::CreateFlexibleBox(*this, legacy_layout); return LayoutObjectFactory::CreateBlockFlow(*this, style, legacy_layout); }
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc index 89d0fcc..d9e756d 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -263,7 +263,7 @@ LayoutObject* HTMLTextAreaElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateTextControlMultiLine(*this, style, legacy); + return LayoutObjectFactory::CreateTextControlMultiLine(*this, legacy); } void HTMLTextAreaElement::AppendToFormData(FormData& form_data) {
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.cc b/third_party/blink/renderer/core/html/forms/range_input_type.cc index f978b04..f58a5393 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -254,7 +254,7 @@ LegacyLayout legacy) const { // TODO(crbug.com/1131352): input[type=range] should not use // LayoutFlexibleBox. - return LayoutObjectFactory::CreateFlexibleBox(GetElement(), style, legacy); + return LayoutObjectFactory::CreateFlexibleBox(GetElement(), legacy); } Decimal RangeInputType::ParseToNumber(const String& src,
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc index 21676c6..872142a 100644 --- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc +++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -327,7 +327,7 @@ LayoutObject* SliderContainerElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateFlexibleBox(*this, style, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*this, legacy); } void SliderContainerElement::DefaultEventHandler(Event& event) {
diff --git a/third_party/blink/renderer/core/html/forms/slider_track_element.cc b/third_party/blink/renderer/core/html/forms/slider_track_element.cc index 55a7d074..01b6f77 100644 --- a/third_party/blink/renderer/core/html/forms/slider_track_element.cc +++ b/third_party/blink/renderer/core/html/forms/slider_track_element.cc
@@ -13,7 +13,7 @@ LayoutObject* SliderTrackElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateSliderTrack(*this, style, legacy); + return LayoutObjectFactory::CreateSliderTrack(*this, legacy); } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc index 17ead81c..a434fb46 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -131,8 +131,7 @@ LayoutObject* TextControlInnerEditorElement::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateTextControlInnerEditor(*this, style, - legacy); + return LayoutObjectFactory::CreateTextControlInnerEditor(*this, legacy); } scoped_refptr<ComputedStyle>
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc index bf44e5b..b55cc1c 100644 --- a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -285,8 +285,7 @@ LayoutObject* TextFieldInputType::CreateLayoutObject( const ComputedStyle& style, LegacyLayout legacy) const { - return LayoutObjectFactory::CreateTextControlSingleLine(GetElement(), style, - legacy); + return LayoutObjectFactory::CreateTextControlSingleLine(GetElement(), legacy); } void TextFieldInputType::CreateShadowSubtree() {
diff --git a/third_party/blink/renderer/core/html/html_progress_element.cc b/third_party/blink/renderer/core/html/html_progress_element.cc index e7ba5e9a..7410e1e 100644 --- a/third_party/blink/renderer/core/html/html_progress_element.cc +++ b/third_party/blink/renderer/core/html/html_progress_element.cc
@@ -54,7 +54,7 @@ } UseCounter::Count(GetDocument(), WebFeature::kProgressElementWithProgressBarAppearance); - return LayoutObjectFactory::CreateProgress(this, style, legacy); + return LayoutObjectFactory::CreateProgress(this, legacy); } LayoutProgress* HTMLProgressElement::GetLayoutProgress() const {
diff --git a/third_party/blink/renderer/core/html/html_rt_element.cc b/third_party/blink/renderer/core/html/html_rt_element.cc index 548e222..8b3921c7 100644 --- a/third_party/blink/renderer/core/html/html_rt_element.cc +++ b/third_party/blink/renderer/core/html/html_rt_element.cc
@@ -17,7 +17,7 @@ LayoutObject* HTMLRTElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { if (style.Display() == EDisplay::kBlock) - return LayoutObjectFactory::CreateRubyText(this, style, legacy); + return LayoutObjectFactory::CreateRubyText(this, legacy); return LayoutObject::CreateObject(this, style, legacy); }
diff --git a/third_party/blink/renderer/core/html/html_ruby_element.cc b/third_party/blink/renderer/core/html/html_ruby_element.cc index 96c3ae0..d0cbef5 100644 --- a/third_party/blink/renderer/core/html/html_ruby_element.cc +++ b/third_party/blink/renderer/core/html/html_ruby_element.cc
@@ -20,7 +20,7 @@ return new LayoutRubyAsInline(this); if (style.Display() == EDisplay::kBlock) { UseCounter::Count(GetDocument(), WebFeature::kRubyElementWithDisplayBlock); - return LayoutObjectFactory::CreateRubyAsBlock(this, style, legacy); + return LayoutObjectFactory::CreateRubyAsBlock(this, legacy); } return LayoutObject::CreateObject(this, style, legacy); }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index 079c7fb..2c4bff5 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -59,6 +59,7 @@ #include "third_party/blink/renderer/core/core_initializer.h" #include "third_party/blink/renderer/core/core_probes_inl.h" #include "third_party/blink/renderer/core/css/media_list.h" +#include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/dom/attribute.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h" @@ -703,6 +704,10 @@ DVLOG(2) << "parseAttribute(" << *this << ", kSrcAttr, old=" << params.old_value << ", new=" << params.new_value << ")"; + // A change to the src attribute can affect intrinsic size, which in turn + // requires a style recalc. + SetNeedsStyleRecalc(kLocalStyleChange, + StyleChangeReasonForTracing::FromAttribute(name)); // Trigger a reload, as long as the 'src' attribute is present. if (!params.new_value.IsNull()) { ignore_preload_none_ = false;
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index 0e17a62..7dc28895 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -1016,7 +1016,8 @@ InspectorPageAgent::ToResourceType(resource_type); WillSendRequestInternal(loader, fetch_context_url, request, - ResourceResponse(), options, type); + ResourceResponse(), options, type, + base::TimeTicks::Now()); String request_id = IdentifiersFactory::RequestId(loader, request.InspectorId()); @@ -1057,7 +1058,8 @@ const ResourceRequest& request, const ResourceResponse& redirect_response, const ResourceLoaderOptions& options, - InspectorPageAgent::ResourceType type) { + InspectorPageAgent::ResourceType type, + base::TimeTicks timestamp) { String loader_id = IdentifiersFactory::LoaderId(loader); String request_id = IdentifiersFactory::RequestId(loader, request.InspectorId()); @@ -1127,8 +1129,8 @@ maybe_frame_id = frame_id; GetFrontend()->requestWillBeSent( request_id, loader_id, documentURL, std::move(request_info), - base::TimeTicks::Now().since_origin().InSecondsF(), - base::Time::Now().ToDoubleT(), std::move(initiator_object), + timestamp.since_origin().InSecondsF(), base::Time::Now().ToDoubleT(), + std::move(initiator_object), BuildObjectForResourceResponse(redirect_response), resource_type, std::move(maybe_frame_id), request.HasUserGesture()); if (options.synchronous_policy == SynchronousPolicy::kRequestSynchronously) @@ -1261,7 +1263,8 @@ const ResourceResponse& redirect_response, const ResourceLoaderOptions& options, ResourceType resource_type, - RenderBlockingBehavior render_blocking_behavior) { + RenderBlockingBehavior render_blocking_behavior, + base::TimeTicks timestamp) { // Ignore the request initiated internally. if (options.initiator_info.name == fetch_initiator_type_names::kInternal) return; @@ -1270,7 +1273,7 @@ InspectorPageAgent::ToResourceType(resource_type); WillSendRequestInternal(loader, fetch_context_url, request, redirect_response, - options, type); + options, type, timestamp); } void InspectorNetworkAgent::MarkResourceAsCached(DocumentLoader* loader,
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.h b/third_party/blink/renderer/core/inspector/inspector_network_agent.h index b4173970..ec74040 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.h
@@ -108,7 +108,8 @@ const ResourceResponse& redirect_response, const ResourceLoaderOptions&, ResourceType, - RenderBlockingBehavior); + RenderBlockingBehavior, + base::TimeTicks timestamp); void WillSendNavigationRequest(uint64_t identifier, DocumentLoader*, const KURL&, @@ -272,7 +273,8 @@ const ResourceRequest&, const ResourceResponse& redirect_response, const ResourceLoaderOptions&, - InspectorPageAgent::ResourceType); + InspectorPageAgent::ResourceType, + base::TimeTicks timestamp); bool CanGetResponseBodyBlob(const String& request_id); void GetResponseBodyBlob(const String& request_id,
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc index 7603fe7..995ab53e9 100644 --- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc +++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -125,11 +125,16 @@ const ResourceResponse& redirect_response, const ResourceLoaderOptions&, ResourceType, - RenderBlockingBehavior render_blocking_behavior) { + RenderBlockingBehavior render_blocking_behavior, + base::TimeTicks timestamp) { LocalFrame* frame = loader ? loader->GetFrame() : nullptr; - DEVTOOLS_TIMELINE_TRACE_EVENT_INSTANT( - "ResourceSendRequest", inspector_send_request_event::Data, loader, - request.InspectorId(), frame, request, render_blocking_behavior); + TRACE_EVENT_INSTANT_WITH_TIMESTAMP1( + "devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, + timestamp, "data", [&](perfetto::TracedValue ctx) { + inspector_send_request_event::Data(std::move(ctx), loader, + request.InspectorId(), frame, + request, render_blocking_behavior); + }); } void InspectorTraceEvents::WillSendNavigationRequest(
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.h b/third_party/blink/renderer/core/inspector/inspector_trace_events.h index 14ffd41..1976e6c 100644 --- a/third_party/blink/renderer/core/inspector/inspector_trace_events.h +++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.h
@@ -93,7 +93,8 @@ const ResourceResponse& redirect_response, const ResourceLoaderOptions&, ResourceType, - RenderBlockingBehavior); + RenderBlockingBehavior, + base::TimeTicks timestamp); void WillSendNavigationRequest(uint64_t identifier, DocumentLoader*, const KURL&,
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index bddde61..011d045 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -2270,11 +2270,11 @@ parent->UpdateAnonymousChildStyle(nullptr, *new_style); LayoutBlock* layout_block; if (new_display == EDisplay::kFlex) { - layout_block = LayoutObjectFactory::CreateFlexibleBox(parent->GetDocument(), - *new_style, legacy); + layout_block = + LayoutObjectFactory::CreateFlexibleBox(parent->GetDocument(), legacy); } else if (new_display == EDisplay::kGrid) { - layout_block = LayoutObjectFactory::CreateGrid(parent->GetDocument(), - *new_style, legacy); + layout_block = + LayoutObjectFactory::CreateGrid(parent->GetDocument(), legacy); } else { DCHECK(new_display == EDisplay::kBlock || new_display == EDisplay::kFlowRoot);
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 564d550..f53e6b9 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -288,38 +288,37 @@ return LayoutObjectFactory::CreateBlockFlow(*element, style, legacy); case EDisplay::kTable: case EDisplay::kInlineTable: - return LayoutObjectFactory::CreateTable(*element, style, legacy); + return LayoutObjectFactory::CreateTable(*element, legacy); case EDisplay::kTableRowGroup: case EDisplay::kTableHeaderGroup: case EDisplay::kTableFooterGroup: - return LayoutObjectFactory::CreateTableSection(*element, style, legacy); + return LayoutObjectFactory::CreateTableSection(*element, legacy); case EDisplay::kTableRow: - return LayoutObjectFactory::CreateTableRow(*element, style, legacy); + return LayoutObjectFactory::CreateTableRow(*element, legacy); case EDisplay::kTableColumnGroup: case EDisplay::kTableColumn: - return LayoutObjectFactory::CreateTableColumn(*element, style, legacy); + return LayoutObjectFactory::CreateTableColumn(*element, legacy); case EDisplay::kTableCell: - return LayoutObjectFactory::CreateTableCell(*element, style, legacy); + return LayoutObjectFactory::CreateTableCell(*element, legacy); case EDisplay::kTableCaption: - return LayoutObjectFactory::CreateTableCaption(*element, style, legacy); + return LayoutObjectFactory::CreateTableCaption(*element, legacy); case EDisplay::kWebkitBox: case EDisplay::kWebkitInlineBox: if (style.IsDeprecatedWebkitBoxWithVerticalLineClamp()) { - return LayoutObjectFactory::CreateBlockForLineClamp(*element, style, - legacy); + return LayoutObjectFactory::CreateBlockForLineClamp(*element, legacy); } - return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*element, legacy); case EDisplay::kFlex: case EDisplay::kInlineFlex: UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox); - return LayoutObjectFactory::CreateFlexibleBox(*element, style, legacy); + return LayoutObjectFactory::CreateFlexibleBox(*element, legacy); case EDisplay::kGrid: case EDisplay::kInlineGrid: UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout); - return LayoutObjectFactory::CreateGrid(*element, style, legacy); + return LayoutObjectFactory::CreateGrid(*element, legacy); case EDisplay::kMath: case EDisplay::kBlockMath: - return LayoutObjectFactory::CreateMath(*element, style, legacy); + return LayoutObjectFactory::CreateMath(*element, legacy); case EDisplay::kLayoutCustom: case EDisplay::kInlineLayoutCustom: DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc index 6906d4f..8cd5dc09 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.cc +++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -121,21 +121,18 @@ // static LayoutBlock* LayoutObjectFactory::CreateBlockForLineClamp( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutDeprecatedFlexibleBox>(node, legacy); } LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGFlexibleBox, LayoutFlexibleBox>( node, legacy); } LayoutBlock* LayoutObjectFactory::CreateGrid(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGGridEnabled(); if (disable_ng_for_type) @@ -145,7 +142,6 @@ } LayoutBlock* LayoutObjectFactory::CreateMath(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { DCHECK(IsA<MathMLElement>(node)); DCHECK_NE(legacy, LegacyLayout::kForce); @@ -183,7 +179,6 @@ } LayoutBlock* LayoutObjectFactory::CreateTable(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -194,14 +189,12 @@ LayoutTableCaption* LayoutObjectFactory::CreateTableCaption( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutTableCaption, LayoutNGTableCaption>(node, legacy); } LayoutBlockFlow* LayoutObjectFactory::CreateTableCell( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) { return CreateObject<LayoutBlockFlow, LayoutNGTableCell, LayoutTableCell>( @@ -213,7 +206,6 @@ } LayoutBox* LayoutObjectFactory::CreateTableColumn(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -223,7 +215,6 @@ } LayoutBox* LayoutObjectFactory::CreateTableRow(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -233,7 +224,6 @@ } LayoutBox* LayoutObjectFactory::CreateTableSection(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled(); if (disable_ng_for_type) @@ -243,13 +233,11 @@ } LayoutObject* LayoutObjectFactory::CreateButton(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGButton, LayoutButton>(node, legacy); } LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(node, legacy); @@ -257,14 +245,12 @@ LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow, LayoutFileUploadControl>(node, legacy); } LayoutObject* LayoutObjectFactory::CreateSliderTrack(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutSliderTrack>( node, legacy); @@ -272,7 +258,6 @@ LayoutObject* LayoutObjectFactory::CreateTextControlInnerEditor( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlInnerEditor, LayoutTextControlInnerEditor>(node, legacy); @@ -280,7 +265,6 @@ LayoutObject* LayoutObjectFactory::CreateTextControlMultiLine( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlMultiLine, LayoutTextControlMultiLine>(node, legacy); @@ -288,7 +272,6 @@ LayoutObject* LayoutObjectFactory::CreateTextControlSingleLine( Node& node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutBlockFlow, LayoutNGTextControlSingleLine, LayoutTextControlSingleLine>(node, legacy); @@ -329,26 +312,22 @@ } LayoutProgress* LayoutObjectFactory::CreateProgress(Node* node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutProgress, LayoutNGProgress>(*node, legacy); } LayoutRubyAsBlock* LayoutObjectFactory::CreateRubyAsBlock( Node* node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutRubyAsBlock, LayoutNGRubyAsBlock>(*node, legacy); } LayoutObject* LayoutObjectFactory::CreateRubyText(Node* node, - const ComputedStyle& style, LegacyLayout legacy) { return CreateObject<LayoutRubyText, LayoutNGRubyText>(*node, legacy); } LayoutObject* LayoutObjectFactory::CreateSVGText(Node& node, - const ComputedStyle& style, LegacyLayout legacy) { const bool disable_ng_for_type = !RuntimeEnabledFeatures::SVGTextNGEnabled(); return CreateObject<LayoutBlockFlow, LayoutNGSVGText, LayoutSVGText>( @@ -376,8 +355,7 @@ ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBlock* new_table = - CreateTable(parent.GetDocument(), *new_style, legacy); + LayoutBlock* new_table = CreateTable(parent.GetDocument(), legacy); new_table->SetDocumentForAnonymous(&parent.GetDocument()); new_table->SetStyle(std::move(new_style)); return new_table; @@ -391,8 +369,7 @@ LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBox* new_section = - CreateTableSection(parent.GetDocument(), *new_style, legacy); + LayoutBox* new_section = CreateTableSection(parent.GetDocument(), legacy); new_section->SetDocumentForAnonymous(&parent.GetDocument()); new_section->SetStyle(std::move(new_style)); return new_section; @@ -405,7 +382,7 @@ parent.StyleRef(), EDisplay::kTableRow); LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBox* new_row = CreateTableRow(parent.GetDocument(), *new_style, legacy); + LayoutBox* new_row = CreateTableRow(parent.GetDocument(), legacy); new_row->SetDocumentForAnonymous(&parent.GetDocument()); new_row->SetStyle(std::move(new_style)); return new_row; @@ -418,8 +395,7 @@ parent.StyleRef(), EDisplay::kTableCell); LegacyLayout legacy = parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto; - LayoutBlockFlow* new_cell = - CreateTableCell(parent.GetDocument(), *new_style, legacy); + LayoutBlockFlow* new_cell = CreateTableCell(parent.GetDocument(), legacy); new_cell->SetDocumentForAnonymous(&parent.GetDocument()); new_cell->SetStyle(std::move(new_style)); return new_cell;
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h index 1c53fd7..e4824706 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory.h +++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -41,50 +41,38 @@ const ComputedStyle&, LegacyLayout); static LayoutBlock* CreateBlockForLineClamp(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutBlock* CreateFlexibleBox(Node&, - const ComputedStyle&, LegacyLayout); - static LayoutBlock* CreateGrid(Node&, const ComputedStyle&, LegacyLayout); - static LayoutBlock* CreateMath(Node&, const ComputedStyle&, LegacyLayout); + static LayoutBlock* CreateGrid(Node&, LegacyLayout); + static LayoutBlock* CreateMath(Node&, LegacyLayout); static LayoutObject* CreateListMarker(Node&, const ComputedStyle&, LegacyLayout); - static LayoutBlock* CreateTable(Node&, const ComputedStyle&, LegacyLayout); + static LayoutBlock* CreateTable(Node&, LegacyLayout); static LayoutTableCaption* CreateTableCaption(Node&, - const ComputedStyle&, LegacyLayout); static LayoutBlockFlow* CreateTableCell(Node&, - const ComputedStyle&, LegacyLayout); static LayoutBox* CreateTableColumn(Node&, - const ComputedStyle&, LegacyLayout); - static LayoutBox* CreateTableRow(Node&, const ComputedStyle&, LegacyLayout); + static LayoutBox* CreateTableRow(Node&, LegacyLayout); static LayoutBox* CreateTableSection(Node&, - const ComputedStyle&, LegacyLayout); static LayoutObject* CreateButton(Node& node, - const ComputedStyle& style, LegacyLayout legacy); - static LayoutBlock* CreateFieldset(Node&, const ComputedStyle&, LegacyLayout); + static LayoutBlock* CreateFieldset(Node&, LegacyLayout); static LayoutBlockFlow* CreateFileUploadControl(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateSliderTrack(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlInnerEditor(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlMultiLine(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateTextControlSingleLine(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutText* CreateText(Node*, scoped_refptr<StringImpl>, LegacyLayout); @@ -94,17 +82,13 @@ int length, LegacyLayout); static LayoutProgress* CreateProgress(Node* node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutRubyAsBlock* CreateRubyAsBlock(Node* node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateRubyText(Node* node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateSVGText(Node& node, - const ComputedStyle& style, LegacyLayout legacy); static LayoutObject* CreateBR(Node*, LegacyLayout);
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory_test.cc b/third_party/blink/renderer/core/layout/layout_object_factory_test.cc index d1eedc52..b2141ca 100644 --- a/third_party/blink/renderer/core/layout/layout_object_factory_test.cc +++ b/third_party/blink/renderer/core/layout/layout_object_factory_test.cc
@@ -35,4 +35,14 @@ EXPECT_FALSE(layout_object.IsLayoutNGObject()); } +TEST_P(LayoutObjectFactoryTest, WordBreak) { + SetBodyInnerHTML("<wbr id=sample>"); + const auto& layout_object = *GetLayoutObjectByElementId("sample"); + + if (LayoutNGEnabled()) + EXPECT_TRUE(layout_object.IsLayoutNGObject()); + else + EXPECT_FALSE(layout_object.IsLayoutNGObject()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc index e30bc902..9b4f0fcc 100644 --- a/third_party/blink/renderer/core/layout/layout_table_cell.cc +++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -1227,7 +1227,7 @@ scoped_refptr<ComputedStyle> style, LegacyLayout legacy) { LayoutBlockFlow* layout_object = - LayoutObjectFactory::CreateTableCell(*document, *style, legacy); + LayoutObjectFactory::CreateTableCell(*document, legacy); layout_object->SetDocumentForAnonymous(document); layout_object->SetStyle(std::move(style)); return To<LayoutTableCell>(layout_object);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index b3a608a..b977ecd 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -2973,6 +2973,12 @@ // precedence. Returns 'true' if |a| < |b| and 'false' otherwise. auto IsBeforeInGridOrder = [&](const GridArea& a, const GridArea& b) -> bool { + // Do not consider items that span tracks for container baselines. + if (a.rows.IntegerSpan() > 1 || a.columns.IntegerSpan() > 1 || + b.rows.IntegerSpan() > 1 || b.columns.IntegerSpan() > 1) { + return false; + } + return (a.rows < b.rows) || (a.rows == b.rows && (a.columns < b.columns)); }; @@ -2994,9 +3000,7 @@ // Propagate the baseline from the appropriate child. // TODO(kschmi): Synthesize baseline from alignment context if no grid items. if (!grid_items.IsEmpty()) { - if (alignment_baseline && - (!fallback_baseline || alignment_baseline->resolved_position.rows <= - fallback_baseline->resolved_position.rows)) { + if (alignment_baseline) { container_builder_.SetBaseline(alignment_baseline->baseline); } else { DCHECK(fallback_baseline);
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc index c637297..f30d9417 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.cc
@@ -496,7 +496,8 @@ builder.SetTableCellBorders(cell_borders); builder.SetTableCellAlignmentBaseline(alignment_baseline); builder.SetTableCellColumnIndex(column_index); - builder.SetIsRestrictedBlockSizeTableCell(is_table_block_size_specified); + builder.SetIsRestrictedBlockSizeTableCell( + is_table_block_size_specified || !cell_style.LogicalHeight().IsAuto()); builder.SetIsTableCellHiddenForPaint(is_hidden_for_paint); builder.SetIsTableCellWithCollapsedBorders(has_collapsed_borders); builder.SetHideTableCellIfEmpty(
diff --git a/third_party/blink/renderer/core/loader/document_load_timing.cc b/third_party/blink/renderer/core/loader/document_load_timing.cc index 56d4471a..a43e765 100644 --- a/third_party/blink/renderer/core/loader/document_load_timing.cc +++ b/third_party/blink/renderer/core/loader/document_load_timing.cc
@@ -38,7 +38,10 @@ namespace blink { DocumentLoadTiming::DocumentLoadTiming(DocumentLoader& document_loader) - : redirect_count_(0), + : user_timing_mark_fully_loaded_(absl::nullopt), + user_timing_mark_fully_visible_(absl::nullopt), + user_timing_mark_interactive_(absl::nullopt), + redirect_count_(0), has_cross_origin_redirect_(false), can_request_from_previous_document_(false), clock_(base::DefaultClock::GetInstance()),
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc index 8925c1c..f1dc930 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
@@ -91,7 +91,7 @@ GetProbe(), document_loader_, fetcher_properties_->GetFetchClientSettingsObject().GlobalObjectUrl(), request, redirect_response, options, resource_type, - render_blocking_behavior); + render_blocking_behavior, base::TimeTicks::Now()); if (auto* idleness_detector = frame->GetIdlenessDetector()) idleness_detector->OnWillSendRequest(document_->Fetcher()); if (auto* interactive_detector = InteractiveDetector::From(*document_))
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc index 3cd73224..b952abff 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc
@@ -39,7 +39,7 @@ probe_, nullptr, fetcher_properties_->GetFetchClientSettingsObject().GlobalObjectUrl(), request, redirect_response, options, resource_type, - render_blocking_behavior); + render_blocking_behavior, base::TimeTicks::Now()); } void ResourceLoadObserverForWorker::DidChangePriority(
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc index 5d411e0..030322d 100644 --- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc +++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -440,6 +440,10 @@ !base::FeatureList::IsEnabled(features::kAppCache)) { return false; } + if (trial_name == "ComputePressure" && + !base::FeatureList::IsEnabled(features::kComputePressure)) { + return false; + } if (trial_name == "FledgeInterestGroupAPI" && !base::FeatureList::IsEnabled(features::kFledgeInterestGroups)) { return false;
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 index 2ce8e7d..66327a8 100644 --- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 +++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5
@@ -308,5 +308,10 @@ permissions_policy_name: "xr-spatial-tracking", depends_on: ["WebXR"], }, + { + name: "WindowPlacement", + permissions_policy_name: "window-placement", + depends_on: ["WindowPlacement"], + }, ], }
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl index 3f58882a..c2cf11a 100644 --- a/third_party/blink/renderer/core/probe/core_probes.pidl +++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -91,7 +91,7 @@ void DidBlockRequest(CoreProbeSink*, const ResourceRequest&, DocumentLoader*, const KURL& fetch_context_url, const ResourceLoaderOptions&, ResourceRequestBlockedReason, ResourceType); void DidChangeResourcePriority(LocalFrame*, DocumentLoader*, uint64_t identifier, ResourceLoadPriority load_priority); void PrepareRequest(CoreProbeSink*, DocumentLoader*, ResourceRequest&, ResourceLoaderOptions&, ResourceType); - void WillSendRequest(CoreProbeSink*, DocumentLoader*, const KURL& fetch_context_url, const ResourceRequest&, const ResourceResponse& redirect_response, const ResourceLoaderOptions&, ResourceType, RenderBlockingBehavior); + void WillSendRequest(CoreProbeSink*, DocumentLoader*, const KURL& fetch_context_url, const ResourceRequest&, const ResourceResponse& redirect_response, const ResourceLoaderOptions&, ResourceType, RenderBlockingBehavior, base::TimeTicks timestamp); void WillSendNavigationRequest(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const KURL&, const AtomicString& http_method, EncodedFormData*); void MarkResourceAsCached(LocalFrame*, DocumentLoader*, uint64_t identifier); void DidReceiveResourceResponse(CoreProbeSink*, uint64_t identifier, DocumentLoader*, const ResourceResponse&, const Resource*);
diff --git a/third_party/blink/renderer/core/svg/svg_text_element.cc b/third_party/blink/renderer/core/svg/svg_text_element.cc index e311c65..0e9a2d1 100644 --- a/third_party/blink/renderer/core/svg/svg_text_element.cc +++ b/third_party/blink/renderer/core/svg/svg_text_element.cc
@@ -29,7 +29,7 @@ LayoutObject* SVGTextElement::CreateLayoutObject(const ComputedStyle& style, LegacyLayout legacy) { - return LayoutObjectFactory::CreateSVGText(*this, style, legacy); + return LayoutObjectFactory::CreateSVGText(*this, legacy); } } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_timing.cc b/third_party/blink/renderer/core/timing/performance_timing.cc index 58a026f6..7838348 100644 --- a/third_party/blink/renderer/core/timing/performance_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -666,6 +666,8 @@ absl::optional<base::TimeDelta> PerformanceTiming::UserTimingMarkFullyLoaded() const { DocumentLoadTiming* timing = GetDocumentLoadTiming(); + if (!timing) + return absl::nullopt; return timing->UserTimingMarkFullyLoaded(); } @@ -673,6 +675,8 @@ absl::optional<base::TimeDelta> PerformanceTiming::UserTimingMarkFullyVisible() const { DocumentLoadTiming* timing = GetDocumentLoadTiming(); + if (!timing) + return absl::nullopt; return timing->UserTimingMarkFullyVisible(); } @@ -680,6 +684,8 @@ absl::optional<base::TimeDelta> PerformanceTiming::UserTimingMarkInteractive() const { DocumentLoadTiming* timing = GetDocumentLoadTiming(); + if (!timing) + return absl::nullopt; return timing->UserTimingMarkInteractive(); }
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index 6461909..c1b9ba12 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -699,6 +699,11 @@ } void MediaControlsImpl::UpdateCSSClassFromState() { + // Skip CSS class updates when not needed in order to avoid triggering + // unnecessary style calculation. + if (!MediaElement().ShouldShowControls() && !is_hiding_controls_) + return; + const ControlsState state = State(); Vector<String> toAdd; @@ -959,6 +964,8 @@ } void MediaControlsImpl::Hide() { + base::AutoReset<bool> auto_reset_hiding_controls(&is_hiding_controls_, true); + panel_->SetIsWanted(false); panel_->SetIsDisplayed(false);
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h index e64e1ec5e..07e1ad1 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -401,6 +401,12 @@ bool is_paused_for_scrubbing_ : 1; bool is_scrubbing_ = false; + // When controls are hidden, we defer CSS updates on them in order to avoid + // unnecessary style calculation. When controls transition from shown to + // hidden, we set this flag to true to ensure that one final style update + // takes place in order to eliminate states such as scrubbing. + bool is_hiding_controls_ = false; + // Watches the video element for resize and updates media controls as // necessary. Member<ResizeObserver> resize_observer_;
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc index b556f28..1b53f8fc 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -208,6 +208,22 @@ void SimulateOnSeeking() { media_controls_->OnSeeking(); } void SimulateOnSeeked() { media_controls_->OnSeeked(); } + void SimulateOnWaiting() { media_controls_->OnWaiting(); } + void SimulateOnPlaying() { media_controls_->OnPlaying(); } + + void SimulateMediaControlPlaying() { + MediaControls().MediaElement().SetReadyState( + HTMLMediaElement::kHaveEnoughData); + MediaControls().MediaElement().SetNetworkState( + WebMediaPlayer::NetworkState::kNetworkStateLoading); + } + + void SimulateMediaControlBuffering() { + MediaControls().MediaElement().SetReadyState( + HTMLMediaElement::kHaveCurrentData); + MediaControls().MediaElement().SetNetworkState( + WebMediaPlayer::NetworkState::kNetworkStateLoading); + } MediaControlsImpl& MediaControls() { return *media_controls_; } MediaControlVolumeSliderElement* VolumeSliderElement() const { @@ -1293,4 +1309,84 @@ EXPECT_EQ(30, MediaControls().MediaElement().currentTime()); } +TEST_F(MediaControlsImplTest, HideControlsDefersStyleCalculationOnPlaying) { + MediaControls().MediaElement().SetBooleanAttribute(html_names::kControlsAttr, + false); + MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); + MediaControls().MediaElement().Play(); + test::RunPendingTasks(); + + Element* panel = GetElementByShadowPseudoId(MediaControls(), + "-webkit-media-controls-panel"); + ASSERT_NE(nullptr, panel); + EXPECT_FALSE(IsElementVisible(*panel)); + UpdateAllLifecyclePhasesForTest(); + Document& document = this->GetDocument(); + EXPECT_FALSE(document.NeedsLayoutTreeUpdate()); + + int old_element_count = document.GetStyleEngine().StyleForElementCount(); + + SimulateMediaControlPlaying(); + SimulateOnPlaying(); + EXPECT_EQ(MediaControls().State(), + MediaControlsImpl::ControlsState::kPlaying); + + // With the controls hidden, playback state change should not trigger style + // calculation. + EXPECT_FALSE(document.NeedsLayoutTreeUpdate()); + UpdateAllLifecyclePhasesForTest(); + int new_element_count = document.GetStyleEngine().StyleForElementCount(); + EXPECT_EQ(old_element_count, new_element_count); + + MediaControls().MediaElement().SetBooleanAttribute(html_names::kControlsAttr, + true); + EXPECT_TRUE(IsElementVisible(*panel)); + + // Showing the controls should trigger the deferred style calculation. + EXPECT_TRUE(document.NeedsLayoutTreeUpdate()); + UpdateAllLifecyclePhasesForTest(); + new_element_count = document.GetStyleEngine().StyleForElementCount(); + EXPECT_LT(old_element_count, new_element_count); +} + +TEST_F(MediaControlsImplTest, HideControlsDefersStyleCalculationOnWaiting) { + MediaControls().MediaElement().SetBooleanAttribute(html_names::kControlsAttr, + false); + MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4"); + MediaControls().MediaElement().Play(); + test::RunPendingTasks(); + + Element* panel = GetElementByShadowPseudoId(MediaControls(), + "-webkit-media-controls-panel"); + ASSERT_NE(nullptr, panel); + EXPECT_FALSE(IsElementVisible(*panel)); + UpdateAllLifecyclePhasesForTest(); + Document& document = this->GetDocument(); + EXPECT_FALSE(document.NeedsLayoutTreeUpdate()); + + int old_element_count = document.GetStyleEngine().StyleForElementCount(); + + SimulateMediaControlBuffering(); + SimulateOnWaiting(); + EXPECT_EQ(MediaControls().State(), + MediaControlsImpl::ControlsState::kBuffering); + + // With the controls hidden, playback state change should not trigger style + // calculation. + EXPECT_FALSE(document.NeedsLayoutTreeUpdate()); + UpdateAllLifecyclePhasesForTest(); + int new_element_count = document.GetStyleEngine().StyleForElementCount(); + EXPECT_EQ(old_element_count, new_element_count); + + MediaControls().MediaElement().SetBooleanAttribute(html_names::kControlsAttr, + true); + EXPECT_TRUE(IsElementVisible(*panel)); + + // Showing the controls should trigger the deferred style calculation. + EXPECT_TRUE(document.NeedsLayoutTreeUpdate()); + UpdateAllLifecyclePhasesForTest(); + new_element_count = document.GetStyleEngine().StyleForElementCount(); + EXPECT_LT(old_element_count, new_element_count); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index eb69d7d..14e454de 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -388,6 +388,8 @@ status: "experimental", }, { + // blink::features::kComputePressure is a kill switch for the API. If the + // feature is disabled, origin trial tokens are ignored. name: "ComputePressure", origin_trial_feature_name: "ComputePressure", status: "experimental",
diff --git a/third_party/blink/tools/move_blink_source.py b/third_party/blink/tools/move_blink_source.py deleted file mode 100755 index e3567ee..0000000 --- a/third_party/blink/tools/move_blink_source.py +++ /dev/null
@@ -1,799 +0,0 @@ -#!/usr/bin/env vpython -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Tool to move Blink source from third_party/WebKit to third_party/blink. - -See https://docs.google.com/document/d/1l3aPv1Wx__SpRkdOhvJz8ciEGigNT3wFKv78XiuW0Tw/edit?usp=sharing#heading=h.o225wrxp242h -for the details. -""" - -import argparse -import logging -import os -import platform -import re -import sys -from functools import partial - -sys.path.append( - os.path.join( - os.path.dirname(__file__), '..', 'renderer', 'build', 'scripts')) -from blinkbuild.name_style_converter import NameStyleConverter -from blinkpy.common.checkout.git import Git -from blinkpy.common.path_finder import get_chromium_src_dir -from blinkpy.common.path_finder import get_blink_tools_dir -from blinkpy.common.system.executive import Executive -from blinkpy.common.system.executive import ScriptError -from blinkpy.common.system.filesystem import FileSystem -from blinkpy.common.system.platform_info import PlatformInfo -from plan_blink_move import plan_blink_move -from plan_blink_move import relative_dest - -_log = logging.getLogger('move_blink_source') - - -class FileType(object): - NONE = 0 - BUILD = 1 - BLINK_BUILD = 2 - OWNERS = 3 - DEPS = 4 - MOJOM = 5 - TYPEMAP = 6 - BLINK_BUILD_PY = 7 - LAYOUT_TESTS_WITH_MOJOM = 8 - BLINK_DEPS = 9 - - @staticmethod - def detect(path): - slash_dir, basename = os.path.split(path) - slash_dir = slash_dir.replace(os.path.sep, '/') - if basename == 'DEPS': - if 'third_party/WebKit' in path: - return FileType.BLINK_DEPS - return FileType.DEPS - if basename == 'OWNERS': - return FileType.OWNERS - if basename.endswith('.mojom'): - return FileType.MOJOM - if basename.endswith('.typemap'): - return FileType.TYPEMAP - if basename.endswith( - '.py') and 'third_party/WebKit/Source/build' in slash_dir: - return FileType.BLINK_BUILD_PY - if basename.endswith(('.gn', '.gni')): - if 'third_party/WebKit' in path or 'third_party/blink' in slash_dir: - return FileType.BLINK_BUILD - if 'third_party' in slash_dir: - return FileType.NONE - return FileType.BUILD - if basename.endswith('.html') and re.search( - r'third_party/WebKit/LayoutTests/(' - r'fast/dom/shadow|' - r'fast/forms/color|' - r'geolocation-api|' - r'http/tests/budget|' - r'http/tests/credentialmanager|' - r'http/tests/security/powerfulFeatureRestrictions|' - r'installedapp|' - r'media/mediasession|' - r'payments|' - r'presentation|' - r'reporting-observer|' - r'webshare)', slash_dir): - return FileType.LAYOUT_TESTS_WITH_MOJOM - return FileType.NONE - - -class MoveBlinkSource(object): - def __init__(self, fs, options, repo_root): - self._fs = fs - self._platform = PlatformInfo(sys, platform, fs, Executive()) - self._options = options - _log.debug(options) - self._repo_root = repo_root - - # The following fields are initialized in _create_basename_maps. - self._basename_map = None - self._basename_re_list = None - self._idl_generated_impl_headers = None - # _checked_in_header_re_list is used to distinguish checked-in - # header files and generated header files. - self._checked_in_header_re_list = None - - self._updated_files = [] - - def update(self, apply_only=None): - """Updates contents of files affected by Blink source move. - - Args: - apply_only: If it's None, updates all affected files. Otherwise, - it should be a set of file paths and this function updates - only the files in |apply_only|. - """ - _log.info('Planning renaming ...') - file_pairs = plan_blink_move(self._fs, []) - - self._create_basename_maps(file_pairs) - dirs = self._update_file_content(apply_only) - - # Updates #includes in files in directories with updated DEPS + - # third_party/WebKit/{Source,common,public}. - self._append_unless_upper_dir_exists( - dirs, - self._fs.join(self._repo_root, 'third_party', 'WebKit', 'Source')) - self._append_unless_upper_dir_exists( - dirs, - self._fs.join(self._repo_root, 'third_party', 'WebKit', 'common')) - self._append_unless_upper_dir_exists( - dirs, - self._fs.join(self._repo_root, 'third_party', 'WebKit', 'public')) - self._append_unless_upper_dir_exists( - dirs, - self._fs.join(self._repo_root, 'mojo', 'public', 'tools', - 'bindings', 'generators', 'cpp_templates')) - self._update_cpp_includes_in_directories(dirs, apply_only) - - # Content update for individual files. - # The following is a list of tuples. - # Tuple: (<file path relative to repo root>, [replacement commands]) - # Command: a callable object, or - # a tuple of (<original string>, <new string>). - file_replacement_list = [ - ('DEPS', [('src/third_party/WebKit/Source/devtools', - 'src/third_party/blink/renderer/devtools')]), - ('WATCHLISTS', - [('third_party/WebKit/Source', 'third_party/blink/renderer'), - ('third_party/WebKit/public', 'third_party/blink/public')]), - ('build/check_gn_headers_whitelist.txt', - [('third_party/WebKit/Source', 'third_party/blink/renderer'), - ('third_party/WebKit/public', 'third_party/blink/public'), - self._update_basename]), - ('chrome/browser/resources/chromeos/accessibility/chromevox/tools/jsbundler.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('testing/buildbot/gn_isolate_map.pyl', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('third_party/WebKit/Source/BUILD.gn', - [('$root_gen_dir/third_party/WebKit', - '$root_gen_dir/third_party/blink')]), - ('third_party/WebKit/Source/config.gni', - [('snake_case_source_files = false', - 'snake_case_source_files = true')]), - ('third_party/WebKit/Source/core/css/CSSProperties.json5', - [self._update_basename]), - ('third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5', - [self._update_basename]), - ('third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5', - [self._update_basename]), - ('third_party/WebKit/Source/core/html/parser/create-html-entity-table', - [self._update_basename]), - ('third_party/WebKit/Source/core/inspector/inspector_protocol_config.json', - [self._update_basename]), - ('third_party/WebKit/Source/core/probe/CoreProbes.json5', - [self._update_basename]), - ('third_party/WebKit/Source/core/testing/InternalSettings.h', - [('InternalSettingsGenerated.h', - 'internal_settings_generated.h')]), - ('third_party/WebKit/Source/core/testing/Internals.cpp', - [('InternalRuntimeFlags.h', 'internal_runtime_flags.h')]), - ('third_party/WebKit/Source/platform/probe/PlatformProbes.json5', - [self._update_basename]), - ('third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer'), - ('ls-files third_party/WebKit', 'ls-files third_party/blink')]), - ('third_party/WebKit/Tools/Scripts/webkitpy/style/checker.py', - [('Source/', 'renderer/')]), - ('third_party/WebKit/public/BUILD.gn', - [('$root_gen_dir/third_party/WebKit', - '$root_gen_dir/third_party/blink')]), - ('third_party/WebKit/public/blink_resources.grd', - [('../Source/', '../renderer/')]), - ('third_party/blink/tools/compile_devtools_frontend.py', - [('\'WebKit\', \'Source\'', '\'blink\', \'renderer\'')]), - ('tools/android/eclipse/.classpath', - [('third_party/WebKit/public', 'third_party/blink/public')]), - ('tools/android/loading/cloud/backend/deploy.sh', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/android/loading/emulation_unittest.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/android/loading/options.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/android/loading/request_track.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/cfi/blacklist.txt', [('third_party/WebKit/Source', - 'third_party/blink/renderer')]), - ('tools/gritsettings/resource_ids', - [('third_party/WebKit/public', 'third_party/blink/public'), - ('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/include_tracer.py', [('third_party/WebKit/Source', - 'third_party/blink/renderer')]), - ('tools/metrics/actions/extract_actions.py', - [('third_party/WebKit/Source', 'third_party/blink/renderer')]), - ('tools/metrics/histograms/update_editor_commands.py', - [('third_party/WebKit/Source/core/editing/EditorCommand.cpp', - 'third_party/blink/renderer/core/editing/editor_command.cc')]), - ('tools/metrics/histograms/update_use_counter_css.py', - [('third_party/WebKit/Source/core/frame/UseCounter.cpp', - 'third_party/blink/renderer/core/frame/use_counter.cc')]), - ('tools/metrics/histograms/update_use_counter_feature_enum.py', - [('third_party/WebKit/public', 'third_party/blink/public')]), - ] - for file_path, replacement_list in file_replacement_list: - if not apply_only or file_path in apply_only: - self._update_single_file_content( - file_path, - replacement_list, - should_write=self._options.run) - - if self._options.run: - _log.info('Formatting updated %d files ...', - len(self._updated_files)) - git = self._create_git() - # |git cl format| can't handle too many files at once. - while len(self._updated_files) > 0: - end_index = 100 - if end_index > len(self._updated_files): - end_index = len(self._updated_files) - git.run(['cl', 'format'] + self._updated_files[:end_index]) - self._updated_files = self._updated_files[end_index:] - - if not apply_only: - _log.info('Make a local commit ...') - git.commit_locally_with_message( - """The Great Blink mv for source files, part 1. - -Update file contents without moving files. - -NOAUTOREVERT=true -NOPRESUBMIT=true -NOTREECHECKS=true -Bug: 768828 -""") - - def move(self, apply_only=None): - """Move Blink source files. - - Args: - apply_only: If it's None, move all affected files. Otherwise, - it should be a set of file paths and this function moves - only the files in |apply_only|. - """ - _log.info('Planning renaming ...') - file_pairs = plan_blink_move(self._fs, []) - - if apply_only: - file_pairs = [ - (src, dest) for (src, dest) in file_pairs - if 'third_party/WebKit/' + src.replace('\\', '/') in apply_only - ] - _log.info('Will move %d files', len(file_pairs)) - - git = self._create_git() - files_set = self._get_checked_in_files(git) - for i, (src, dest) in enumerate(file_pairs): - src_from_repo = self._fs.join('third_party', 'WebKit', src) - if src_from_repo.replace('\\', '/') not in files_set: - _log.info('%s is not in the repository', src) - continue - dest_from_repo = self._fs.join('third_party', 'blink', dest) - self._fs.maybe_make_directory(self._repo_root, 'third_party', - 'blink', self._fs.dirname(dest)) - if self._options.run_git: - git.move(src_from_repo, dest_from_repo) - _log.info('[%d/%d] Git moved %s', i + 1, len(file_pairs), src) - else: - self._fs.move( - self._fs.join(self._repo_root, src_from_repo), - self._fs.join(self._repo_root, dest_from_repo)) - _log.info('[%d/%d] Moved %s', i + 1, len(file_pairs), src) - if apply_only: - return - - self._update_single_file_content('build/get_landmines.py', [( - '\ndef main', - ' print \'The Great Blink mv for source files (crbug.com/768828)\'\n\ndef main' - )]) - - _log.info('Run run_bindings_tests.py ...') - Executive().run_command([ - 'python', - self._fs.join(get_blink_tools_dir(), 'run_bindings_tests.py'), - '--reset-results' - ], - cwd=self._repo_root) - - if self._options.run_git: - _log.info('Make a local commit ...') - git.commit_locally_with_message( - """The Great Blink mv for source files, part 2. - -Move and rename files. - -NOAUTOREVERT=true -NOPRESUBMIT=true -NOTREECHECKS=true -Bug: 768828 -""") - - def fix_branch(self): - git = self._create_git() - status = self._get_local_change_status(git) - if len(status) == 0: - _log.info('No local changes.') - return - modified_files = {f for (s, f) in status if s != 'D'} - deleted_files = {f for (s, f) in status if s == 'D'} - - self.update(apply_only=modified_files) - self.move(apply_only=modified_files) - try: - git.commit_locally_with_message('This commit should be squashed.') - except ScriptError: - _log.info('move_blink_source.py modified nothing.') - - # TODO(tkent): Show a message about deleted_files. - - def _get_local_change_status(self, git): - """Returns a list of tuples representing local change summary. - - Each tuple contains two strings. The first one is file change status - such as "M", "D". See --diff-filter section of git-diff manual page. - The second one is file name relative to the repository top. - """ - - base_commit = git.run( - ['show-branch', '--merge-base', 'master', 'HEAD']).strip() - # Note that file names in the following command result are always - # slash-separated, even on Windows. - status_lines = git.run( - ['diff', '--name-status', '--no-renames', base_commit]).split('\n') - status_tuple_list = [] - for l in status_lines: - items = l.split('\t') - if len(items) == 2: - status_tuple_list.append(tuple(items)) - elif len(l) > 0: - _log.warning('Unrecognized diff output: "%s"', l) - return status_tuple_list - - def _get_checked_in_files(self, git): - files_text = git.run([ - 'ls-files', 'third_party/WebKit/Source', - 'third_party/WebKit/common', 'third_party/WebKit/public' - ]) - return set(files_text.split('\n')) - - def _create_basename_maps(self, file_pairs): - basename_map = {} - basenames = [] - idl_headers = set() - headers = [] - for source, dest in file_pairs: - _, source_base = self._fs.split(source) - _, dest_base = self._fs.split(dest) - # OriginTrialFeaturesForCore.h in bindings/tests/results/modules/ - # confuses generated/checked-in detection in _replace_include_path(). - if 'bindings/tests' in source.replace('\\', '/'): - continue - if source_base.endswith('.h'): - headers.append(re.escape(source_base)) - if source_base == dest_base: - continue - basename_map[source_base] = dest_base - basenames.append(re.escape(source_base)) - # IDL sometimes generates implementation files as well as - # binding files. We'd like to update #includes for such files. - if source_base.endswith('.idl'): - source_header = source_base.replace('.idl', '.h') - basename_map[source_header] = dest_base.replace('.idl', '.h') - basenames.append(re.escape(source_header)) - idl_headers.add(source_header) - elif source_base.endswith('.proto'): - source_header = source_base.replace('.proto', '.pb.h') - basename_map[source_header] = dest_base.replace( - '.proto', '.pb.h') - basenames.append(re.escape(source_header)) - _log.debug('Rename %d files for snake_case', len(basename_map)) - self._basename_map = basename_map - self._idl_generated_impl_headers = idl_headers - - self._basename_re_list = [] - self._checked_in_header_re_list = [] - # Split file names into some chunks to avoid "Regular expression - # code size limit exceeded" on Windows - CHUNK_SIZE = 700 - # Generated inspector/protocol/* contains a lot of names duplicated with - # checked-in core files. We don't want to rename them, and don't want to - # replace them in BUILD.gn and #include accidentally. - RE_PREFIX = r'(?<!inspector/protocol/)' - - while len(basenames) > 0: - end_index = min(CHUNK_SIZE, len(basenames)) - self._basename_re_list.append( - re.compile(RE_PREFIX + r'\b(' + - '|'.join(basenames[0:end_index]) + ')(?=["\']|$)')) - basenames = basenames[end_index:] - - while len(headers) > 0: - end_index = min(CHUNK_SIZE, len(headers)) - self._checked_in_header_re_list.append( - re.compile(RE_PREFIX + r'\b(' + - '|'.join(headers[0:end_index]) + ')$')) - headers = headers[end_index:] - - def _shorten_path(self, path): - if path.startswith(self._repo_root): - return path[len(self._repo_root) + 1:] - return path - - @staticmethod - def _filter_file(fs, dirname, basename): - return FileType.detect(fs.join(dirname, basename)) != FileType.NONE - - def _update_build(self, content): - content = content.replace('//third_party/WebKit/Source', - '//third_party/blink/renderer') - content = content.replace('//third_party/WebKit/common', - '//third_party/blink/common') - content = content.replace('//third_party/WebKit/public', - '//third_party/blink/public') - # export_header_blink exists outside of Blink too. - content = content.replace( - 'export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"', - 'export_header_blink = "third_party/blink/public/platform/web_common.h"' - ) - content = content.replace('$root_gen_dir/blink/public', - '$root_gen_dir/third_party/blink/public') - content = content.replace('$root_gen_dir/blink', - '$root_gen_dir/third_party/blink/renderer') - return content - - def _update_blink_build(self, content): - content = self._update_build(content) - - # Update visibility=[...] - content = content.replace('//third_party/WebKit/*', - '//third_party/blink/*') - content = content.replace('//third_party/WebKit/Source/*', - '//third_party/blink/renderer/*') - content = content.replace('//third_party/WebKit/public/*', - '//third_party/blink/public/*') - - # Update mojom variables - content = content.replace('export_header = "third_party/WebKit/common', - 'export_header = "third_party/blink/common') - content = content.replace( - 'export_header_blink = "third_party/WebKit/Source', - 'export_header_blink = "third_party/blink/renderer') - - # Update buildflag_header() rules - content = content.replace('header_dir = "blink/', - 'header_dir = "third_party/blink/renderer/') - - return self._update_basename(content) - - def _update_owners(self, content): - content = content.replace('//third_party/WebKit/Source', - '//third_party/blink/renderer') - content = content.replace('//third_party/WebKit/common', - '//third_party/blink/common') - content = content.replace('//third_party/WebKit/public', - '//third_party/blink/public') - return content - - def _update_deps(self, content): - original_content = content - content = content.replace('third_party/WebKit/Source', - 'third_party/blink/renderer') - content = content.replace('third_party/WebKit/common', - 'third_party/blink/common') - content = content.replace('third_party/WebKit/public', - 'third_party/blink/public') - content = content.replace('third_party/WebKit', 'third_party/blink') - if original_content == content: - return content - return self._update_basename(content) - - def _update_blink_deps(self, content): - original_content = content - content = re.sub('(?<=[-+!])public', 'third_party/blink/public', - content) - content = re.sub( - '(?<=[-+!])(bindings|controller|core|modules|platform)', - 'third_party/blink/renderer/\\1', content) - content = content.replace('third_party/WebKit', 'third_party/blink') - if original_content == content: - return content - return self._update_basename(content) - - def _update_mojom(self, content): - content = content.replace('third_party/WebKit/public', - 'third_party/blink/public') - content = content.replace('third_party/WebKit/common', - 'third_party/blink/common') - return content - - def _update_typemap(self, content): - content = content.replace('//third_party/WebKit/Source', - '//third_party/blink/renderer') - content = content.replace('//third_party/WebKit/common', - '//third_party/blink/common') - content = content.replace('//third_party/WebKit/public', - '//third_party/blink/public') - return self._update_basename(content) - - def _update_blink_build_py(self, content): - # We don't prepend 'third_party/blink/renderer/' to matched basenames - # because it won't affect build and manual update after the great mv is - # enough. - return self._update_basename(content) - - def _update_layout_tests(self, content): - return content.replace('file:///gen/third_party/WebKit/public/', - 'file:///gen/third_party/blink/public/') - - def _update_basename(self, content): - for regex in self._basename_re_list: - content = regex.sub( - lambda match: self._basename_map[match.group(1)], content) - return content - - @staticmethod - def _append_unless_upper_dir_exists(dirs, new_dir): - for i in range(0, len(dirs)): - if new_dir.startswith(dirs[i]): - return - if dirs[i].startswith(new_dir): - dirs[i] = new_dir - return - dirs.append(new_dir) - - def _update_file_content(self, apply_only): - _log.info('Find *.gn, *.mojom, *.py, *.typemap, DEPS, and OWNERS ...') - files = self._fs.files_under( - self._repo_root, - dirs_to_skip=['.git', 'out'], - file_filter=self._filter_file) - _log.info('Scan contents of %d files ...', len(files)) - updated_deps_dirs = [] - for file_path in files: - file_type = FileType.detect(file_path) - original_content = self._fs.read_text_file(file_path) - content = original_content - if file_type == FileType.BUILD: - content = self._update_build(content) - elif file_type == FileType.BLINK_BUILD: - content = self._update_blink_build(content) - elif file_type == FileType.OWNERS: - content = self._update_owners(content) - elif file_type == FileType.DEPS: - if self._fs.dirname(file_path) == self._repo_root: - _log.debug("Skip //DEPS") - continue - content = self._update_deps(content) - elif file_type == FileType.BLINK_DEPS: - content = self._update_blink_deps(content) - elif file_type == FileType.MOJOM: - content = self._update_mojom(content) - elif file_type == FileType.TYPEMAP: - content = self._update_typemap(content) - elif file_type == FileType.BLINK_BUILD_PY: - content = self._update_blink_build_py(content) - elif file_type == FileType.LAYOUT_TESTS_WITH_MOJOM: - content = self._update_layout_tests(content) - - if original_content == content: - continue - if self._options.run and (not apply_only or file_path.replace( - '\\', '/') in apply_only): - self._fs.write_text_file(file_path, content) - self._updated_files.append(file_path) - _log.info('Updated %s', self._shorten_path(file_path)) - if file_type == FileType.DEPS: - self._append_unless_upper_dir_exists( - updated_deps_dirs, self._fs.dirname(file_path)) - return updated_deps_dirs - - def _update_cpp_includes_in_directories(self, dirs, apply_only): - for dirname in dirs: - _log.info('Processing #include in %s ...', - self._shorten_path(dirname)) - files = self._fs.files_under( - dirname, - file_filter= - lambda fs, _, basename: basename.endswith(('.h', '.cc', '.cpp', '.mm', '.cc.tmpl', '.cpp.tmpl', '.h.tmpl', 'xpath_grammar.y', '.gperf')) - ) - for file_path in files: - posix_file_path = file_path.replace('\\', '/') - if '/third_party/WebKit/Source/bindings/tests/results/' in posix_file_path: - continue - original_content = self._fs.read_text_file(file_path) - - content = self._update_cpp_includes(original_content) - if file_path.endswith( - '.h' - ) and '/third_party/WebKit/public/' in posix_file_path: - content = self._update_basename_only_includes( - content, file_path) - if file_path.endswith( - '.h') and '/third_party/WebKit/' in posix_file_path: - content = self._update_include_guard(content, file_path) - - if original_content == content: - continue - if self._options.run and (not apply_only - or posix_file_path in apply_only): - self._fs.write_text_file(file_path, content) - self._updated_files.append(file_path) - _log.info('Updated %s', self._shorten_path(file_path)) - - def _replace_include_path(self, match): - include_or_import = match.group(1) - path = match.group(2) - - # If |path| starts with 'blink/public/resources', we should prepend - # 'third_party/'. - # - # If |path| starts with 'third_party/WebKit', we should adjust the - # directory name for third_party/blink, and replace its basename by - # self._basename_map. - # - # If |path| starts with a Blink-internal directory such as bindings, - # core, modules, platform, public, it refers to a checked-in file, or a - # generated file. For the former, we should add 'third_party/blink/' and - # replace the basename. For the latter, we should update the basename - # for a name mapped from an IDL renaming, and should add - # 'third_party/blink/'. - - if path.startswith('blink/public/resources'): - path = path.replace('blink/public', 'third_party/blink/public') - return '#%s "%s"' % (include_or_import, path) - - if path.startswith('third_party/WebKit'): - path = path.replace('third_party/WebKit/Source', - 'third_party/blink/renderer') - path = path.replace('third_party/WebKit/common', - 'third_party/blink/common') - path = path.replace('third_party/WebKit/public', - 'third_party/blink/public') - path = self._update_basename(path) - return '#%s "%s"' % (include_or_import, path) - - match = None - for regex in self._checked_in_header_re_list: - match = regex.search(path) - if match: - break - if match: - if match.group(1) in self._basename_map: - path = path[:match.start(1)] + self._basename_map[match.group( - 1)] - elif 'core/inspector/protocol/' not in path: - basename_start = path.rfind('/') + 1 - basename = path[basename_start:] - if basename in self._idl_generated_impl_headers: - path = path[:basename_start] + self._basename_map[basename] - elif basename.startswith('V8'): - path = path[:basename_start] + NameStyleConverter( - basename[:len(basename) - 2]).to_snake_case() + '.h' - if path.startswith('public'): - path = 'third_party/blink/' + path - else: - path = 'third_party/blink/renderer/' + path - return '#%s "%s"' % (include_or_import, path) - - def _update_cpp_includes(self, content): - pattern = re.compile( - r'#(include|import)\s+"((bindings|controller|core|modules|platform|public|' - + - r'third_party/WebKit/(Source|common|public)|blink/public/resources)/[-_\w/.]+)"' - ) - return pattern.sub(self._replace_include_path, content) - - def _replace_basename_only_include(self, subdir, source_path, match): - source_basename = match.group(1) - if source_basename in self._basename_map: - return '#include "third_party/blink/public/%s/%s"' % ( - subdir, self._basename_map[source_basename]) - _log.warning('Basename-only %s in %s', match.group(0), - self._shorten_path(source_path)) - return match.group(0) - - def _update_basename_only_includes(self, content, source_path): - if not source_path.endswith( - '.h' - ) or '/third_party/WebKit/public/' not in source_path.replace( - '\\', '/'): - return - # In public/ header files, we should replace |#include "WebFoo.h"| - # with |#include "third_party/blink/public/platform-or-web/web_foo.h"| - subdir = self._fs.basename(self._fs.dirname(source_path)) - # subdir is 'web' or 'platform'. - return re.sub( - r'#include\s+"(\w+\.h)"', - partial(self._replace_basename_only_include, subdir, source_path), - content) - - def _update_include_guard(self, content, source_path): - current_guard = re.sub(r'[-.]', '_', self._fs.basename(source_path)) - new_path = relative_dest( - self._fs, - self._fs.relpath( - source_path, - start=self._fs.join(self._repo_root, 'third_party', 'WebKit'))) - new_guard = 'THIRD_PARTY_BLINK_' + re.sub(r'[-\\/.]', '_', - new_path.upper()) + '_' - content = re.sub(r'#ifndef\s+(WTF_)?' + current_guard, - '#ifndef ' + new_guard, content) - content = re.sub(r'#define\s+(WTF_)?' + current_guard, - '#define ' + new_guard, content) - content = re.sub(r'#endif\s+//\s+(WTF_)?' + current_guard, - '#endif // ' + new_guard, content) - return content - - def _update_single_file_content(self, - file_path, - replace_list, - should_write=True): - full_path = self._fs.join(self._repo_root, file_path) - original_content = self._fs.read_text_file(full_path) - content = original_content - for command in replace_list: - if isinstance(command, tuple): - src, dest = command - content = content.replace(src, dest) - elif callable(command): - content = command(content) - else: - raise TypeError('A tuple or a function is expected.') - if content != original_content: - if should_write: - self._fs.write_text_file(full_path, content) - self._updated_files.append(full_path) - _log.info('Updated %s', file_path) - else: - _log.warning('%s does not contain specified source strings.', - file_path) - - def _create_git(self): - return Git( - cwd=self._repo_root, filesystem=self._fs, platform=self._platform) - - -def main(): - logging.basicConfig( - level=logging.INFO, - format='[%(asctime)s %(levelname)s %(name)s] %(message)s', - datefmt='%H:%M:%S') - parser = argparse.ArgumentParser(description='Blink source mover') - sub_parsers = parser.add_subparsers() - - update_parser = sub_parsers.add_parser('update') - update_parser.set_defaults(command='update') - update_parser.add_argument( - '--run', dest='run', action='store_true', help='Update file contents') - - move_parser = sub_parsers.add_parser('move') - move_parser.set_defaults(command='move') - move_parser.add_argument( - '--git', - dest='run_git', - action='store_true', - help='Run |git mv| command instead of |mv|.') - - fixbranch_parser = sub_parsers.add_parser('fixbranch') - fixbranch_parser.set_defaults(command='fixbranch', run=True, run_git=True) - - options = parser.parse_args() - mover = MoveBlinkSource(FileSystem(), options, get_chromium_src_dir()) - if options.command == 'update': - mover.update() - elif options.command == 'move': - mover.move() - elif options.command == 'fixbranch': - mover.fix_branch() - - -if __name__ == '__main__': - main()
diff --git a/third_party/blink/tools/plan_blink_move.py b/third_party/blink/tools/plan_blink_move.py deleted file mode 100755 index 3de4469..0000000 --- a/third_party/blink/tools/plan_blink_move.py +++ /dev/null
@@ -1,95 +0,0 @@ -#!/usr/bin/env vpython -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import re -import sys - -sys.path.append( - os.path.join( - os.path.dirname(__file__), '..', 'renderer', 'build', 'scripts')) -from blinkbuild.name_style_converter import NameStyleConverter -from blinkpy.common.system.filesystem import FileSystem - - -def relative_dest(fs, filename): - """Returns a destination path string for given filename. - - |filename| is a path relative to third_party/WebKit, and the resultant path - is relative to third_party/blink. - """ - dest = None - if filename.startswith('Source'): - dest = re.sub(r'^Source', 'renderer', filename) - elif filename.startswith('common') or filename.startswith('public'): - dest = filename - else: - raise ValueError( - '|filename| must start with "common", "public", or "Source": %s' % - filename) - if filename.endswith(('.h', '.cpp', '.mm', '.idl', '.typemap', '.proto', - 'Settings.json5')): - dirname, basename = fs.split(dest) - basename, ext = fs.splitext(basename) - # Skip some inspector-related files. #includes for these files are - # generated by a script outside of Blink. - if (re.match(r'Inspector.*Agent', basename) - or basename.startswith('AdTracker') - or basename == 'InspectorTraceEvents' - or basename == 'PerformanceMonitor' - or basename == 'PlatformTraceEventsAgent'): - return dest - if filename.endswith('.cpp'): - ext = '.cc' - # WebKit.h should be renamed to blink.h. - if basename == 'WebKit' and ext == '.h': - basename = 'blink' - if basename.lower() != basename: - basename = NameStyleConverter(basename).to_snake_case() - return fs.join(dirname, basename + ext) - return dest - - -def start_with_list(name, prefixes): - if len(prefixes) == 0: - return True - for prefix in prefixes: - if name.startswith(prefix): - return True - return False - - -def plan_blink_move(fs, prefixes): - """Returns (source, dest) path pairs. - - The source paths are relative to third_party/WebKit, - and the dest paths are relative to third_party/blink. - The paths use os.sep as the path part separator. - """ - blink_dir = fs.join(fs.dirname(__file__), '..') - webkit_dir = fs.join(blink_dir, '..', '..', 'third_party', 'WebKit') - source_files = fs.files_under(fs.join(webkit_dir, 'Source')) - source_files += fs.files_under(fs.join(webkit_dir, 'common')) - source_files += fs.files_under(fs.join(webkit_dir, 'public')) - - # It's possible to check git.exists() here, but we don't do it due to slow - # performance. We should check it just before executing git command. - - source_files = [f[len(webkit_dir) + 1:] for f in source_files] - return [(f, relative_dest(fs, f)) for f in source_files - if f.find('node_modules') == -1 and start_with_list(f, prefixes)] - - -def main(): - fs = FileSystem() - file_pairs = plan_blink_move(fs, sys.argv[1:]) - print 'Show renaming plan. It contains files not in the repository.' - print '<Source path relative to third_party/WebKit> => <Destination path relative to third_party/blink>' - for pair in file_pairs: - print '%s\t=>\t%s' % pair - - -if __name__ == '__main__': - main()
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 18d9070..2cae442 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -4008,6 +4008,7 @@ crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-031.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-035.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-036.html [ Failure ] +crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-baseline-004.html [ Failure ] crbug.com/941987 external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-001.html [ Failure ] @@ -4115,6 +4116,7 @@ virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-031.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-035.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-036.html [ Pass ] +virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-004.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-001.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/replaced-alignment-with-aspect-ratio-002.html [ Pass ] @@ -4148,7 +4150,6 @@ ### Tests failing with LayoutNGGrid enabled: crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-abspos-staticpos-align-self-safe-001.html [ Failure ] -crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-004.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-001.html [ Failure ] @@ -6942,7 +6943,6 @@ # Failing css-transforms-2 web platform tests. crbug.com/753080 external/wpt/css/css-transforms/transform3d-sorting-002.html [ Failure ] crbug.com/753080 external/wpt/css/css-transforms/transform3d-sorting-006.html [ Failure ] -crbug.com/753080 external/wpt/css/css-transforms/ttwf-css-3d-polygon-cycle.html [ Failure ] external/wpt/css/css-transforms/2d-rotate-001.html [ Failure ] external/wpt/css/css-transforms/css-skew-002.html [ Failure ] @@ -7095,3 +7095,8 @@ external/wpt/css/css-transforms/ttwf-transform-skewy-001.html [ Failure ] external/wpt/css/css-transforms/ttwf-transform-translatex-001.html [ Failure ] +# Sheriff 2021-05-18 +crbug.com/1210658 [ Mac10.14 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ] +crbug.com/1210658 [ Mac10.15 ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ] +crbug.com/1210658 [ Win ] virtual/jxl-enabled/images/jxl/jxl-images.html [ Failure ] +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004-expected.txt deleted file mode 100644 index 7d26c42..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -PASS .grid, container 1 -PASS .grid, container 2 -PASS .grid, container 3 -PASS .grid, container 4 -PASS .grid, container 5 -PASS .grid, container 6 -PASS .grid, container 7 -PASS .grid, container 8 -PASS .grid, container 9 -PASS .grid, container 10 -PASS .grid, container 11 -PASS .grid, container 12 -PASS .grid, container 13 -PASS .grid, container 14 -PASS .grid, container 15 -FAIL .grid, container 16 assert_equals: -<div class="container" data-expected-width="480" data-expected-height="250"> - <div id="first" class="grid twoRows" data-offset-x="0" data-offset-y="80"> - <div class="firstRowFirstColumn target" data-offset-x="0" data-offset-y="0"></div> - <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> - <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> - </div> - <div id="second" class="grid threeRows" data-offset-x="160" data-offset-y="55"> - <div class="thirdRowFirstColumn" data-offset-x="0" data-offset-y="100"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="65"></div> - <div class="secondRowSecondColumn style3 alignSelfBaseline target" id="first" data-offset-x="0" data-offset-y="80"></div> - </div> - <div class="grid empty threeRows" data-offset-x="320" data-offset-y="15"> - <div class="thirdRowSecondColumn" data-offset-x="50" data-offset-y="110"></div> - <div class="secondRowFirstColumn target" data-offset-x="0" data-offset-y="60"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="75"></div> - </div> -</div> -height expected 250 but got 300 -FAIL .grid, container 17 assert_equals: -<div class="container" data-expected-width="480" data-expected-height="250"> - <div id="first" class="grid twoRows" data-offset-x="0" data-offset-y="80"> - <div class="firstRowFirstColumn target" data-offset-x="0" data-offset-y="0"></div> - <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> - <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> - </div> - <div id="second" class="grid threeRows" data-offset-x="160" data-offset-y="55"> - <div class="thirdRowFirstColumn" data-offset-x="0" data-offset-y="100"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="65"></div> - <div class="secondRowSecondColumn style3 alignSelfBaseline target" id="first" data-offset-x="0" data-offset-y="80"></div> - </div> - <div class="grid empty threeRows" data-offset-x="320" data-offset-y="15"> - <div class="thirdRowSecondColumn" data-offset-x="50" data-offset-y="110"></div> - <div class="secondRowFirstColumn target" data-offset-x="0" data-offset-y="60"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="75"></div> - </div> -</div> -height expected 250 but got 300 -FAIL .grid, container 18 assert_equals: -<div class="container" data-expected-width="480" data-expected-height="250"> - <div id="first" class="grid twoRows" data-offset-x="0" data-offset-y="80"> - <div class="firstRowFirstColumn target" data-offset-x="0" data-offset-y="0"></div> - <div class="firstRowBothColumn" data-offset-x="0" data-offset-y="15"></div> - <div class="bothRowFirstColumn" data-offset-x="0" data-offset-y="10"></div> - </div> - <div id="second" class="grid threeRows" data-offset-x="160" data-offset-y="55"> - <div class="thirdRowFirstColumn" data-offset-x="0" data-offset-y="100"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="65"></div> - <div class="secondRowSecondColumn style3 alignSelfBaseline target" id="first" data-offset-x="0" data-offset-y="80"></div> - </div> - <div class="grid empty threeRows" data-offset-x="320" data-offset-y="15"> - <div class="thirdRowSecondColumn" data-offset-x="50" data-offset-y="110"></div> - <div class="secondRowFirstColumn target" data-offset-x="0" data-offset-y="60"></div> - <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="75"></div> - </div> -</div> -height expected 250 but got 300 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004.html b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004.html index 7c3e46c..cd565a10 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-baseline-004.html
@@ -210,7 +210,7 @@ <div id=second class="grid threeRows" data-offset-x="160" data-offset-y="55"> <div class="thirdRowFirstColumn" data-offset-x="0" data-offset-y="100"></div> <div class="secondRowBothColumn" data-offset-x="0" data-offset-y="65"></div> - <div class="secondRowSecondColumn style3 alignSelfBaseline target" id="first" data-offset-x="0" data-offset-y="80"></div> + <div class="secondRowSecondColumn style3 alignSelfBaseline target" id="first" data-offset-x="50" data-offset-y="60"></div> </div> <div class="grid empty threeRows" data-offset-x="320" data-offset-y="15"> <div class="thirdRowSecondColumn" data-offset-x="50" data-offset-y="110"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure-ref.html b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure-ref.html new file mode 100644 index 0000000..d4e3ec6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure-ref.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background: green;"> + <div style="overflow: auto; height: 100%;"> + <div style="height: 200px;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure.html b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure.html new file mode 100644 index 0000000..c092d0c1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/table-cell-child-overflow-measure.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1210436"> +<link rel="match" href="table-cell-child-overflow-measure-ref.html"> +<div style="width: 100px; height: 100px; display: table-cell; background: green;"> + <div style="overflow: auto; height: 100%;"> + <div style="height: 200px;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/transform3d-sorting-006.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform3d-sorting-006.html index d40edf0..966549a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-transforms/transform3d-sorting-006.html +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform3d-sorting-006.html
@@ -12,9 +12,9 @@ <body> <div style="transform-style: preserve-3d"> <div style="height: 100px; width: 100px; background: red; - transform: rotateX(45deg) rotateY(45deg)"></div> + transform: rotateX(-45deg) rotateY(-45deg)"></div> <div style="height: 100px; width: 100px; background: green; - transform: translateY(-100px) rotateX(45deg) rotateY(-45deg)"></div> + transform: translateY(-100px) rotateX(-45deg) rotateY(45deg)"></div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/ttwf-css-3d-polygon-cycle.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/ttwf-css-3d-polygon-cycle.html index ec33e7d..bd18d20f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-transforms/ttwf-css-3d-polygon-cycle.html +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/ttwf-css-3d-polygon-cycle.html
@@ -2,48 +2,51 @@ <html> <!-- Submitted from TestTWF Paris --> <head> - <title>CSS Transforms Test: 3d transform polygon cycle</title> - <link rel="author" title="Leo Ziegler" href="mailto:leo.ziegler@gmail.com"> - <link rel="help" href="http://www.w3.org/TR/css-transforms-2/#3d-transform-rendering"> - <!-- See also: http://http://en.wikipedia.org/wiki/Newell's_algorithm --> - <link rel="match" href="reference/ttwf-css-3d-polygon-cycle-ref.html"> - <meta name="flags" content="svg"> - <meta name="assert" content="The red, green and blue rectangles are forming a cycle, which should be detected and rendered using Newell Algorithm's."> - <style type="text/css"> - #container { - position: absolute; - top: 100px; - left: 100px; - } - .rect { - position: absolute; - } - #red { - background-color: red; - width: 200px; - height: 50px; - transform: rotateY(20deg); - } - #green { - background-color: green; - width: 50px; - height: 200px; - transform: rotateX(20deg); - } - #blue { - background-color: blue; - width: 50px; - height: 200px; - transform: rotate(45deg) translate(50px, -50px) rotateX(-20deg); - } - </style> + <title>CSS Transforms Test: 3d transform polygon cycle</title> + <link rel="author" title="Leo Ziegler" href="mailto:leo.ziegler@gmail.com"> + <link rel="help" href="http://www.w3.org/TR/css-transforms-2/#3d-transform-rendering"> + <!-- See also: http://http://en.wikipedia.org/wiki/Newell's_algorithm --> + <link rel="match" href="reference/ttwf-css-3d-polygon-cycle-ref.html"> + <meta name=fuzzy content="0-104;0-610"> + <meta name="flags" content="svg"> + <meta name="assert" + content="The red, green and blue rectangles are forming a cycle, which should be detected and rendered using Newell Algorithm's."> + <style type="text/css"> + #container { + position: absolute; + top: 100px; + left: 100px; + transform-style: preserve-3d; + } + .rect { + position: absolute; + } + #red { + background-color: red; + width: 200px; + height: 50px; + transform: rotateY(20deg); + } + #green { + background-color: green; + width: 50px; + height: 200px; + transform: rotateX(20deg); + } + #blue { + background-color: blue; + width: 50px; + height: 200px; + transform: rotate(45deg) translate(50px, -50px) rotateX(-20deg); + } + </style> </head> <body> - <p>The test passes if there red is over green, green is over blue and blue is over red.</p> - <div id="container"> - <div class="rect" id="red"></div> - <div class="rect" id="green"></div> - <div class="rect" id="blue"></div> - </div> + <p>The test passes if there red is over green, green is over blue and blue is over red.</p> + <div id="container"> + <div class="rect" id="red"></div> + <div class="rect" id="green"></div> + <div class="rect" id="blue"></div> + </div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/keypress-dispatch-crash.html b/third_party/blink/web_tests/external/wpt/dom/events/keypress-dispatch-crash.html new file mode 100644 index 0000000..3207adbd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/keypress-dispatch-crash.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="author" title="Robert Flack" href="mailto:flackr@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1209098"> + +<!-- No crash should occur if a keypress is dispatched to a constructed document. --> + +<script> +var newDoc = document.implementation.createDocument( "", null); +var testNode = newDoc.createElement('div'); +newDoc.append(testNode); + +var syntheticEvent = document.createEvent('KeyboardEvents'); +syntheticEvent.initKeyboardEvent("keypress"); +testNode.dispatchEvent(syntheticEvent) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-is-type-supported.html b/third_party/blink/web_tests/external/wpt/media-source/mediasource-is-type-supported.html index f7c6bdc2..1981af7 100644 --- a/third_party/blink/web_tests/external/wpt/media-source/mediasource-is-type-supported.html +++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-is-type-supported.html
@@ -53,6 +53,19 @@ 'video/webm;codecs="mp4a.40.2"', ], false, 'Test invalid mismatch between MIME type and codec ID'); + // Note that, though the user agent might support some subset of + // these for progressive non-MSE playback, the MSE mpeg audio + // bytestream format specification requires there to be no codecs + // parameter. + test_type_support([ + 'audio/mpeg;codecs="mp3"', + 'audio/mpeg;codecs="mp4a.69"', + 'audio/mpeg;codecs="mp4a.6B"', + 'audio/aac;codecs="aac"', + 'audio/aac;codecs="adts"', + 'audio/aac;codecs="mp4a.40"', + ], false, 'Test invalid inclusion of codecs parameter for mpeg audio types'); + test_type_support([ 'audio/mp4;codecs="mp4a"', 'audio/mp4;codecs="mp4a.40"',
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/video/video-poster-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/video/video-poster-expected.txt index 357b992..541d030b 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/video/video-poster-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/video/video-poster-expected.txt
@@ -42,7 +42,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-scrubbing'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [352, 288], "contentsOpaqueForText": true, "drawsContent": false,
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt index de0c785..196e805 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -58,7 +58,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-stopped'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [150, 60], "contentsOpaqueForText": true, "drawsContent": false,
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/android/fullscreen/video-overlay-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/android/fullscreen/video-overlay-scroll-expected.txt index ac02836a..6c7e441 100644 --- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/android/fullscreen/video-overlay-scroll-expected.txt +++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/android/fullscreen/video-overlay-scroll-expected.txt
@@ -1,7 +1,7 @@ { "layers": [ { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='phase-pre-ready state-no-source sizing-small use-default-poster'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source use-default-poster'", "bounds": [800, 600], "contentsOpaque": true, "backgroundColor": "#333333"
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/video/video-poster-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/video/video-poster-expected.txt index a5df5fd..e1f57d4 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/video/video-poster-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/video/video-poster-expected.txt
@@ -48,7 +48,7 @@ "transform": 1 }, { - "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-scrubbing'", + "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [352, 288], "transform": 1 },
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt index 5d5413de..2071ac90 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -64,7 +64,7 @@ "transform": 1 }, { - "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-stopped'", + "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [150, 60], "transform": 1 },
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/android/fullscreen/video-overlay-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/android/fullscreen/video-overlay-scroll-expected.txt index 2a21432..a3dbe67 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/android/fullscreen/video-overlay-scroll-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/android/fullscreen/video-overlay-scroll-expected.txt
@@ -6,7 +6,7 @@ "drawsContent": false }, { - "name": "LayoutFlexibleBox (relative positioned) DIV class='phase-pre-ready state-no-source sizing-small use-default-poster'", + "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source use-default-poster'", "bounds": [800, 600], "contentsOpaque": true, "backgroundColor": "#333333"
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/basic.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/basic.html new file mode 100644 index 0000000..6e3dc7b --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/basic.html
@@ -0,0 +1,9 @@ +<html> + <head> + <link rel="stylesheet" href="inspector-protocol/resources/style.css"></script> + </head> + <body> + <script src="inspector-protocol/resources/empty.js"></script> + <img src="inspector-protocol/resources/square.png"> + </body> +</html>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/tracing-test.js b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/tracing-test.js new file mode 100644 index 0000000..2642270 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/tracing-test.js
@@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(class TracingHelper { + constructor(testRunner, session) { + this._testRunner = testRunner; + this._session = session; + } + + startTracing(categories="-*,disabled-by-default-devtools.timeline,devtools.timeline") { + return this.startTracingWithArguments({ "categories": categories, "type": "", "options": "" }); + } + + startTracingAndSaveAsStream() { + var args = { + "categories": "-*,disabled-by-default-devtools.timeline,devtools.timeline", + "type": "", + "options": "", + "transferMode": "ReturnAsStream" + }; + return this.startTracingWithArguments(args); + } + + async startTracingWithArguments(args) { + await this._session.protocol.Tracing.start(args); + this._testRunner.log("Recording started"); + } + + async stopTracing(filter_re=/devtools.timeline/) { + var devtoolsEvents = []; + + function dataCollected(reply) { + var allEvents = reply.params.value; + var filteredEvents = allEvents.filter(e => filter_re.test(e.cat)); + devtoolsEvents = devtoolsEvents.concat(filteredEvents); + }; + + this._session.protocol.Tracing.onDataCollected(dataCollected); + this._session.protocol.Tracing.end(); + await this._session.protocol.Tracing.onceTracingComplete(); + this._testRunner.log("Tracing complete"); + this._session.protocol.Tracing.offDataCollected(dataCollected); + this._devtoolsEvents = devtoolsEvents; + return devtoolsEvents; + } + + async stopTracingAndReturnStream() { + function dataCollected() { + this._testRunner.log( + "FAIL: dataCollected event should not be fired when returning trace as stream."); + } + + this._session.protocol.Tracing.onDataCollected(dataCollected); + this._session.protocol.Tracing.end(); + var event = await this._session.protocol.Tracing.onceTracingComplete(); + this._testRunner.log("Tracing complete"); + this._session.protocol.Tracing.offDataCollected(dataCollected); + return event.params.stream; + } + + retrieveStream(streamHandle, offset, chunkSize) { + var callback; + var promise = new Promise(f => callback = f); + var result = ""; + var had_eof = false; + + var readArguments = { handle: streamHandle }; + if (typeof chunkSize === "number") + readArguments.size = chunkSize; + var firstReadArguments = JSON.parse(JSON.stringify(readArguments)); + if (typeof offset === "number") + firstReadArguments.offset = offset; + this._session.protocol.IO.read(firstReadArguments).then(message => onChunkRead.call(this, message.result)); + // Assure multiple in-flight reads are fine (also, save on latencies). + this._session.protocol.IO.read(readArguments).then(message => onChunkRead.call(this, message.result)); + return promise; + + function onChunkRead(response) { + if (had_eof) + return; + result += response.data; + if (response.eof) { + // Ignore stray callbacks from proactive read requests. + had_eof = true; + if (response.base64Encoded) + result = atob(result); + callback(result); + return; + } + this._session.protocol.IO.read(readArguments).then(message => onChunkRead.call(this, message.result)); + } + } + + findEvents(name, ph, condition) { + return this._devtoolsEvents.filter(e => e.name === name && e.ph === ph && (!condition || condition(e))); + } + + findEvent(name, ph, condition) { + var events = this.findEvents(name, ph, condition); + if (events.length) + return events[0]; + throw new Error("Couldn't find event " + name + " / " + ph + "\n\n in " + JSON.stringify(this._devtoolsEvents, null, 2)); + } + + filterEvents(callback) { + return this._devtoolsEvents.filter(callback); + } + + async invokeAsyncWithTracing(performActions) { + await this.startTracing(); + var data = await this._session.evaluateAsync(`(${performActions.toString()})()`); + await this.stopTracing(); + return data; + } + + formattedEvents() { + var formattedEvents = this._devtoolsEvents.map(e => e.name + (e.args.data ? '(' + e.args.data.type + ')' : '')); + return JSON.stringify(formattedEvents, null, 2); + } +})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time-expected.txt new file mode 100644 index 0000000..8cb902a --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time-expected.txt
@@ -0,0 +1,8 @@ +Tests requests queueing time consistency beetween the Network and Tracing domains. +Recording started +Tracing complete +Queueing times for URL http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol/resources/empty.js match: true +Queueing times for URL http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol/resources/square.png match: true +Queueing times for URL http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol/resources/style.css match: true +Queueing times for URL http://127.0.0.1:8000/inspector-protocol/resources/basic.html match: true +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time.js b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time.js new file mode 100644 index 0000000..b70b321 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/request-queueing-time.js
@@ -0,0 +1,72 @@ +(async function(testRunner) { + + const {session, dp} = await testRunner.startBlank('Tests requests queueing time consistency beetween the Network and Tracing domains.'); + const resourceSendRequest = 'ResourceSendRequest'; + const resourceWillSendRequest = 'ResourceWillSendRequest'; + // Request count = basic.html + 3 resources. + const requestCount = 4; + + const TracingHelper = await testRunner.loadScript('../resources/tracing-test.js'); + const tracingHelper = new TracingHelper(testRunner, session); + + await tracingHelper.startTracing(); + dp.Network.enable(); + + const requestsFromNetorkDomain = new Map(); + + dp.Network.onRequestWillBeSent(event => { + requestsFromNetorkDomain.set( + event.params.requestId, + { + url: event.params.request.url, + // Timestamp from the network domain arrives in seconds. + // We convert it to microseconds to compare it against + // data coming from the tracing domain. + timestamp: Math.round(event.params.timestamp * 1000 * 1000) + }); + }); + + dp.Page.navigate({url: 'http://127.0.0.1:8000/inspector-protocol/resources/basic.html'}); + + // Wait for traces to show up. + for (let i = 0; i < requestCount; ++i) { + await dp.Network.onceRequestWillBeSent(); + } + + const devtoolsEvents = await tracingHelper.stopTracing(); + + const requestsFromTracingDomain = new Map(); + for (const event of devtoolsEvents) { + if (event.name !== resourceSendRequest && event.name !== resourceWillSendRequest) { + continue; + } + const requestId = event.args.data.requestId; + const cachedEventInfo = requestsFromTracingDomain.get(requestId); + + // If a request is initiated by the browser process the start time is marked by a + // "ResourceWillSendRequest" record. If, instead, the request is initiated by the + // renderer, the time is marked by "ResourceSendRequest" one. In the first case, + // it is possible that a "ResourceSendRequest" is issued as well for the request + // and thus it must be discarded in favor of the time marked by the + // "ResourceWillSendRequest" record. In the latter case, no + // "ResourceWillSendRequest" record is issued for the request. + const mustOverwrite = cachedEventInfo && cachedEventInfo.name === resourceSendRequest && event.name === resourceWillSendRequest; + if (!cachedEventInfo || mustOverwrite) { + // Timestamp from tracing domain arrives in microseconds. + requestsFromTracingDomain.set(requestId, {name: event.name, timestamp: event.ts, url: event.args.data.url} ); + } + } + + const sortedEvents = [...requestsFromTracingDomain.entries()].sort((entry1, entry2) => { + const url1 = entry1[1].url; + const url2 = entry2[1].url; + return url1.localeCompare(url2); + }); + + for (const [requestId, request] of sortedEvents) { + const networkEvent = requestsFromNetorkDomain.get(requestId); + testRunner.log(`Queueing times for URL ${networkEvent.url} match: ${networkEvent.timestamp === request.timestamp}`); + } + + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt index 4fcfc8a..e1d541eb 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 433 tests; 169 PASS, 264 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 393 tests; 166 PASS, 227 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw FAIL URL's href: file://example:1/ should throw assert_throws_js: function "() => url.href = test.input" did not throw @@ -39,10 +39,6 @@ PASS window.open(): http://foo:-80/ should throw PASS URL's constructor's base argument: http:/:@/www.example.com should throw FAIL URL's href: http:/:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://user@/www.example.com should throw FAIL URL's href: http://user@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://user@/www.example.com should throw @@ -51,16 +47,8 @@ PASS window.open(): http://user@/www.example.com should throw PASS URL's constructor's base argument: http:@/www.example.com should throw FAIL URL's href: http:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:/@/www.example.com should throw FAIL URL's href: http:/@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://@/www.example.com should throw FAIL URL's href: http://@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://@/www.example.com should throw @@ -69,22 +57,10 @@ PASS window.open(): http://@/www.example.com should throw PASS URL's constructor's base argument: https:@/www.example.com should throw FAIL URL's href: https:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -PASS XHR: https:@/www.example.com should throw -PASS sendBeacon(): https:@/www.example.com should throw -FAIL Location's href: https:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") -PASS window.open(): https:@/www.example.com should throw PASS URL's constructor's base argument: http:a:b@/www.example.com should throw FAIL URL's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:a:b@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://a:b@/www.example.com should throw FAIL URL's href: http://a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://a:b@/www.example.com should throw @@ -93,10 +69,6 @@ PASS window.open(): http://a:b@/www.example.com should throw PASS URL's constructor's base argument: http::@/www.example.com should throw FAIL URL's href: http::@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http::@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http::@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http::@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http::@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:@:www.example.com should throw FAIL URL's href: http:@:www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw FAIL XHR: http:@:www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw @@ -399,22 +371,10 @@ PASS window.open(): http://[::127.0.0.0.1] should throw PASS URL's constructor's base argument: a should throw FAIL URL's href: a should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a/ should throw FAIL URL's href: a/ should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a// should throw FAIL URL's href: a// should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a// should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a// should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a// should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a// should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: file:///p should throw FAIL URL's href: file:///p should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: file:///p should throw
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt index 6bb81bc..8d43831 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -64,7 +64,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-stopped'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [150, 60], "transform": 1 },
diff --git a/third_party/blink/web_tests/platform/mac/compositing/video/video-poster-expected.txt b/third_party/blink/web_tests/platform/mac/compositing/video/video-poster-expected.txt index a3780a1..80930a2 100644 --- a/third_party/blink/web_tests/platform/mac/compositing/video/video-poster-expected.txt +++ b/third_party/blink/web_tests/platform/mac/compositing/video/video-poster-expected.txt
@@ -48,7 +48,7 @@ "transform": 1 }, { - "name": "LayoutFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-scrubbing'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [352, 288], "transform": 1 },
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt index 4fcfc8a..e1d541eb 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 433 tests; 169 PASS, 264 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 393 tests; 166 PASS, 227 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw FAIL URL's href: file://example:1/ should throw assert_throws_js: function "() => url.href = test.input" did not throw @@ -39,10 +39,6 @@ PASS window.open(): http://foo:-80/ should throw PASS URL's constructor's base argument: http:/:@/www.example.com should throw FAIL URL's href: http:/:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://user@/www.example.com should throw FAIL URL's href: http://user@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://user@/www.example.com should throw @@ -51,16 +47,8 @@ PASS window.open(): http://user@/www.example.com should throw PASS URL's constructor's base argument: http:@/www.example.com should throw FAIL URL's href: http:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:/@/www.example.com should throw FAIL URL's href: http:/@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://@/www.example.com should throw FAIL URL's href: http://@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://@/www.example.com should throw @@ -69,22 +57,10 @@ PASS window.open(): http://@/www.example.com should throw PASS URL's constructor's base argument: https:@/www.example.com should throw FAIL URL's href: https:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -PASS XHR: https:@/www.example.com should throw -PASS sendBeacon(): https:@/www.example.com should throw -FAIL Location's href: https:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") -PASS window.open(): https:@/www.example.com should throw PASS URL's constructor's base argument: http:a:b@/www.example.com should throw FAIL URL's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:a:b@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://a:b@/www.example.com should throw FAIL URL's href: http://a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://a:b@/www.example.com should throw @@ -93,10 +69,6 @@ PASS window.open(): http://a:b@/www.example.com should throw PASS URL's constructor's base argument: http::@/www.example.com should throw FAIL URL's href: http::@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http::@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http::@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http::@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http::@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:@:www.example.com should throw FAIL URL's href: http:@:www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw FAIL XHR: http:@:www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw @@ -399,22 +371,10 @@ PASS window.open(): http://[::127.0.0.0.1] should throw PASS URL's constructor's base argument: a should throw FAIL URL's href: a should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a/ should throw FAIL URL's href: a/ should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a// should throw FAIL URL's href: a// should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a// should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a// should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a// should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a// should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: file:///p should throw FAIL URL's href: file:///p should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: file:///p should throw
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt index 1cb82e7..e03d9f2 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -64,7 +64,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-stopped'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [150, 60], "transform": 1 },
diff --git a/third_party/blink/web_tests/platform/win/compositing/video/video-poster-expected.txt b/third_party/blink/web_tests/platform/win/compositing/video/video-poster-expected.txt index d5ebd23..756deb3a 100644 --- a/third_party/blink/web_tests/platform/win/compositing/video/video-poster-expected.txt +++ b/third_party/blink/web_tests/platform/win/compositing/video/video-poster-expected.txt
@@ -48,7 +48,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-scrubbing'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [352, 288], "transform": 1 },
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt index 3dac586..2541c0b 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/failure-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 433 tests; 170 PASS, 263 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 393 tests; 166 PASS, 227 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL's constructor's base argument: file://example:1/ should throw FAIL URL's href: file://example:1/ should throw assert_throws_js: function "() => url.href = test.input" did not throw @@ -39,10 +39,6 @@ PASS window.open(): http://foo:-80/ should throw PASS URL's constructor's base argument: http:/:@/www.example.com should throw FAIL URL's href: http:/:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://user@/www.example.com should throw FAIL URL's href: http://user@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://user@/www.example.com should throw @@ -51,16 +47,8 @@ PASS window.open(): http://user@/www.example.com should throw PASS URL's constructor's base argument: http:@/www.example.com should throw FAIL URL's href: http:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:/@/www.example.com should throw FAIL URL's href: http:/@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://@/www.example.com should throw FAIL URL's href: http://@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://@/www.example.com should throw @@ -69,22 +57,10 @@ PASS window.open(): http://@/www.example.com should throw PASS URL's constructor's base argument: https:@/www.example.com should throw FAIL URL's href: https:@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -PASS XHR: https:@/www.example.com should throw -PASS sendBeacon(): https:@/www.example.com should throw -FAIL Location's href: https:@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected instance of function "function TypeError() { [native code] }" ("TypeError") -PASS window.open(): https:@/www.example.com should throw PASS URL's constructor's base argument: http:a:b@/www.example.com should throw FAIL URL's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -PASS sendBeacon(): http:a:b@/www.example.com should throw -FAIL Location's href: http:a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" threw object "TypeError: Cannot read property 'close' of null" that is not a DOMException SyntaxError: property "code" is equal to undefined, expected 12 PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http:/a:b@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http://a:b@/www.example.com should throw FAIL URL's href: http://a:b@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: http://a:b@/www.example.com should throw @@ -93,10 +69,6 @@ PASS window.open(): http://a:b@/www.example.com should throw PASS URL's constructor's base argument: http::@/www.example.com should throw FAIL URL's href: http::@/www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: http::@/www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): http::@/www.example.com should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: http::@/www.example.com should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): http::@/www.example.com should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: http:@:www.example.com should throw FAIL URL's href: http:@:www.example.com should throw assert_throws_js: function "() => url.href = test.input" did not throw FAIL XHR: http:@:www.example.com should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw @@ -399,22 +371,10 @@ PASS window.open(): http://[::127.0.0.0.1] should throw PASS URL's constructor's base argument: a should throw FAIL URL's href: a should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a/ should throw FAIL URL's href: a/ should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a/ should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a/ should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a/ should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a/ should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: a// should throw FAIL URL's href: a// should throw assert_throws_js: function "() => url.href = test.input" did not throw -FAIL XHR: a// should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw -FAIL sendBeacon(): a// should throw assert_throws_js: function "() => self.navigator.sendBeacon(test.input)" did not throw -FAIL Location's href: a// should throw assert_throws_js: function "() => self[0].location = test.input" did not throw -FAIL window.open(): a// should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw PASS URL's constructor's base argument: file:///p should throw FAIL URL's href: file:///p should throw assert_throws_js: function "() => url.href = test.input" did not throw PASS XHR: file:///p should throw
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt index fa66bc7..d18100b 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/image/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -64,7 +64,7 @@ "transform": 1 }, { - "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-ready state-stopped'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source'", "bounds": [150, 60], "transform": 1 },
diff --git a/third_party/blink/web_tests/virtual/android/fullscreen/video-overlay-scroll-expected.txt b/third_party/blink/web_tests/virtual/android/fullscreen/video-overlay-scroll-expected.txt index 10bc14ae..a6b22c0 100644 --- a/third_party/blink/web_tests/virtual/android/fullscreen/video-overlay-scroll-expected.txt +++ b/third_party/blink/web_tests/virtual/android/fullscreen/video-overlay-scroll-expected.txt
@@ -6,7 +6,7 @@ "drawsContent": false }, { - "name": "LayoutFlexibleBox (relative positioned) DIV class='phase-pre-ready state-no-source sizing-small use-default-poster'", + "name": "LayoutNGFlexibleBox (relative positioned) DIV class='sizing-small phase-pre-ready state-no-source use-default-poster'", "bounds": [800, 600], "contentsOpaque": true, "backgroundColor": "#333333" @@ -17,7 +17,7 @@ "drawsContent": false }, { - "name": "LayoutFlexibleBox DIV", + "name": "LayoutNGFlexibleBox DIV", "bounds": [800, 600] } ]
diff --git a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt index 59ecdc54..2abc7f4b 100644 --- a/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt +++ b/third_party/blink/web_tests/webexposed/feature-policy-features-expected.txt
@@ -54,5 +54,6 @@ trust-token-redemption usb vertical-scroll +window-placement xr-spatial-tracking
diff --git a/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt b/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt index 80d03c5..98c859e8 100644 --- a/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt +++ b/tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt
@@ -45,7 +45,7 @@ # Populated manually - the rewriter has trouble appending |.get()| inside macros # that work with |XDisplay*|. extensions::GlobalShortcutListenerX11::x_display_ -gl::GLVisualPickerGLX::display_ +ui::VisualPickerGlx::display_ media::(anonymous namespace)::UserInputMonitorLinuxCore::x_record_display_ media::cast::test::LinuxOutputWindow::display_ remoting::(anonymous namespace)::InputInjectorX11::Core::display_
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index d302cbc..9467283 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -99,9 +99,28 @@ 'win') else 'isolate' self.use_luci_auth = False self.rts_out_dir = self.PathJoin('gen', 'rts') + self.banned_from_rts = set() + + def PostArgsInit(self): + self.use_luci_auth = getattr(self.args, 'luci_auth', False) + + if 'config_file' in self.args and self.args.config_file is None: + self.args.config_file = self.default_config + + if 'expectations_dir' in self.args and self.args.expectations_dir is None: + self.args.expectations_dir = os.path.join( + os.path.dirname(self.args.config_file), 'mb_config_expectations') + + if getattr(self.args, 'builder', None): + banned_from_rts_map = json.loads( + self.ReadFile( + self.PathJoin(self.chromium_src_dir, 'tools', 'mb', + 'rts_banned_suites.json'))) + self.banned_from_rts = banned_from_rts_map.get(self.args.builder, set()) def Main(self, args): self.ParseArgs(args) + self.PostArgsInit() try: ret = self.args.func() if ret != 0: @@ -400,15 +419,6 @@ self.args = parser.parse_args(argv) - self.use_luci_auth = getattr(self.args, 'luci_auth', False) - - if 'config_file' in self.args and self.args.config_file is None: - self.args.config_file = self.default_config - - if 'expectations_dir' in self.args and self.args.expectations_dir is None: - self.args.expectations_dir = os.path.join( - os.path.dirname(self.args.config_file), 'mb_config_expectations') - def DumpInputFiles(self): def DumpContentsOfFilePassedTo(arg_name, path): @@ -1216,11 +1226,14 @@ # For more info about RTS, please see # //docs/testing/regression-test-selection.md if self.args.use_rts: - filter_file = target + '.filter' - filter_file_path = self.PathJoin(self.rts_out_dir, filter_file) - if self.Exists(self.ToAbsPath(build_dir, filter_file_path)): - command.append('--test-launcher-filter-file=%s' % filter_file_path) - self.Print('added rts filter file to isolate: %s' % filter_file) + if target in self.banned_from_rts: + self.Print('%s is banned for RTS on this builder' % target) + else: + filter_file = target + '.filter' + filter_file_path = self.PathJoin(self.rts_out_dir, filter_file) + if self.Exists(self.ToAbsPath(build_dir, filter_file_path)): + command.append('--test-launcher-filter-file=%s' % filter_file_path) + self.Print('added RTS filter file to isolate: %s' % filter_file) canonical_target = target.replace(':','_').replace('/','_') ret = self.WriteIsolateFiles(build_dir, command, canonical_target,
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index e5f42ae..759d413 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -23,6 +23,7 @@ 'chromeos-kevin-chrome': 'chromeos_kevin_include_unwind_tables_official', 'chromeos-kevin-chrome-lts': 'chromeos_kevin_include_unwind_tables_official', 'lacros-amd64-generic-chrome': 'chromeos_amd64-generic_lacros_official', + 'lacros-arm-generic-chrome': 'chromeos_arm-generic_lacros_official', # Don't include unwind tables for linux-/mac-/win-/win64-chrome builders. # They monitor binary size growth, which may be affected by the tables. 'linux-chrome': 'official_goma', @@ -889,6 +890,7 @@ 'chromeos-kevin-chrome': 'chromeos_kevin_include_unwind_tables_official', 'chromeos-kevin-compile-chrome': 'chromeos_kevin_include_unwind_tables_official', 'lacros-amd64-generic-chrome': 'chromeos_amd64-generic_lacros_official', + 'lacros-arm-generic-chrome': 'chromeos_arm-generic_lacros_official', 'linux-chrome': 'official_goma', 'linux-chrome-beta': 'official_goma', 'linux-chrome-stable': 'official_goma', @@ -1764,6 +1766,10 @@ 'chromeos_device', 'arm-generic', 'debug', ], + 'chromeos_arm-generic_lacros_official': [ + 'chromeos_arm-generic', 'arm-lacros', 'official', 'minimal_symbols', 'cfi', 'thin_lto', + ], + 'chromeos_arm-generic_lacros_rel': [ 'chromeos_arm-generic', 'arm-lacros', ], @@ -2713,11 +2719,11 @@ ], 'release_trybot_backuprefptr_arm': [ - 'release_trybot', 'backuprefptr', 'android_without_codecs', 'arm', + 'release_trybot', 'backuprefptr', 'android', 'arm', ], 'release_trybot_backuprefptr_arm64': [ - 'release_trybot', 'backuprefptr', 'android_without_codecs', 'arm64', + 'release_trybot', 'backuprefptr', 'android', 'arm64', ], 'release_trybot_paeverywhere_x64': [
diff --git a/tools/mb/mb_config_expectations/chrome.json b/tools/mb/mb_config_expectations/chrome.json index 96061701..fd22328 100644 --- a/tools/mb/mb_config_expectations/chrome.json +++ b/tools/mb/mb_config_expectations/chrome.json
@@ -131,6 +131,42 @@ "use_vaapi": false } }, + "lacros-arm-generic-chrome": { + "args_file": "//build/args/chromeos/arm-generic.gni", + "gn_args": { + "chromeos_is_browser_only": true, + "cros_host_sysroot": "//build/linux/debian_sid_amd64-sysroot", + "cros_v8_snapshot_sysroot": "//build/linux/debian_sid_i386-sysroot", + "enable_linux_installer": false, + "is_cfi": true, + "is_chrome_branded": true, + "is_chromeos_device": true, + "is_official_build": true, + "ozone_platform": "wayland", + "ozone_platform_drm": false, + "ozone_platform_gbm": false, + "ozone_platform_headless": true, + "ozone_platform_wayland": true, + "ozone_platform_x11": false, + "rtc_use_pipewire": false, + "symbol_level": 1, + "target_os": "chromeos", + "use_custom_libcxx": false, + "use_custom_libcxx_for_host": true, + "use_evdev_gestures": false, + "use_gio": false, + "use_glib": false, + "use_goma": true, + "use_gtk": false, + "use_ozone": true, + "use_pangocairo": false, + "use_pulseaudio": false, + "use_system_libsync": false, + "use_thin_lto": true, + "use_v8_context_snapshot": false, + "use_vaapi": false + } + }, "linux-chrome": { "gn_args": { "is_chrome_branded": true,
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json index 897ae19..284c82f4 100644 --- a/tools/mb/mb_config_expectations/chromium.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -383,8 +383,10 @@ "dcheck_always_on": true, "enable_backup_ref_ptr_slow_checks": true, "enable_runtime_backup_ref_ptr_control": true, + "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, + "proprietary_codecs": true, "put_ref_count_in_previous_slot": true, "symbol_level": 1, "target_cpu": "arm", @@ -399,8 +401,10 @@ "dcheck_always_on": true, "enable_backup_ref_ptr_slow_checks": true, "enable_runtime_backup_ref_ptr_control": true, + "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, + "proprietary_codecs": true, "put_ref_count_in_previous_slot": true, "symbol_level": 1, "target_cpu": "arm64",
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.json b/tools/mb/mb_config_expectations/tryserver.chrome.json index 912195e..b1066d8 100644 --- a/tools/mb/mb_config_expectations/tryserver.chrome.json +++ b/tools/mb/mb_config_expectations/tryserver.chrome.json
@@ -155,6 +155,42 @@ "use_vaapi": false } }, + "lacros-arm-generic-chrome": { + "args_file": "//build/args/chromeos/arm-generic.gni", + "gn_args": { + "chromeos_is_browser_only": true, + "cros_host_sysroot": "//build/linux/debian_sid_amd64-sysroot", + "cros_v8_snapshot_sysroot": "//build/linux/debian_sid_i386-sysroot", + "enable_linux_installer": false, + "is_cfi": true, + "is_chrome_branded": true, + "is_chromeos_device": true, + "is_official_build": true, + "ozone_platform": "wayland", + "ozone_platform_drm": false, + "ozone_platform_gbm": false, + "ozone_platform_headless": true, + "ozone_platform_wayland": true, + "ozone_platform_x11": false, + "rtc_use_pipewire": false, + "symbol_level": 1, + "target_os": "chromeos", + "use_custom_libcxx": false, + "use_custom_libcxx_for_host": true, + "use_evdev_gestures": false, + "use_gio": false, + "use_glib": false, + "use_goma": true, + "use_gtk": false, + "use_ozone": true, + "use_pangocairo": false, + "use_pulseaudio": false, + "use_system_libsync": false, + "use_thin_lto": true, + "use_v8_context_snapshot": false, + "use_vaapi": false + } + }, "linux-chrome": { "gn_args": { "is_chrome_branded": true,
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py index 8449108..3d48163 100755 --- a/tools/mb/mb_unittest.py +++ b/tools/mb/mb_unittest.py
@@ -303,6 +303,8 @@ mbw.files.setdefault( mbw.ToAbsPath('//build/args/bots/fake_builder_group/fake_args_bot.gn'), 'is_debug = false\n') + mbw.files.setdefault(mbw.ToAbsPath('//tools/mb/rts_banned_suites.json'), + '{}') if files: for path, contents in files.items(): mbw.files[path] = contents
diff --git a/tools/mb/rts_banned_suites.json b/tools/mb/rts_banned_suites.json new file mode 100644 index 0000000..e8eb8a63 --- /dev/null +++ b/tools/mb/rts_banned_suites.json
@@ -0,0 +1,66 @@ +{ + "linux-rel-rts": [ + "xr_browser_tests", + "hardware_accelerated_feature_tests", + "telemetry_perf_unittests", + "pixel_skia_gold_passthrough_test", + "gl_renderer_screenshot_sync_tests", + "mojo_python_unittests", + "blink_python_tests", + "info_collection_tests", + "telemetry_gpu_unittests", + "depth_capture_tests", + "metrics_python_tests", + "grit_python_unittests", + "webgl_conformance_tests", + "gpu_process_launch_tests", + "maps_pixel_passthrough_test", + "trace_test", + "context_lost_passthrough_tests", + "screenshot_sync_passthrough_tests" + ], + "win10_chromium_x64_rel_ng_rts": [ + "trace_test", + "webgl_conformance_d3d11_passthrough_tests", + "xr_browser_tests", + "info_collection_tests", + "maps_pixel_passthrough_test", + "pixel_skia_gold_passthrough_test", + "metrics_python_tests", + "screenshot_sync_passthrough_tests", + "blink_python_tests", + "gpu_process_launch_tests", + "mojo_python_unittests", + "depth_capture_tests", + "grit_python_unittests", + "hardware_accelerated_feature_tests", + "telemetry_gpu_unittests", + "telemetry_desktop_minidump_unittests", + "context_lost_passthrough_tests" + ], + "fuchsia_x64_rts": [ + "maps_tests", + "hardware_accelerated_feature_tests", + "webgl_conformance_tests", + "trace_test", + "blink_web_tests", + "gpu_process_launch_tests", + "context_lost_validating_tests" + ], + "mac-rel-rts": [ + "trace_test", + "maps_pixel_validating_test", + "screenshot_sync_validating_tests", + "hardware_accelerated_feature_tests", + "webgl_conformance_tests", + "pixel_skia_gold_validating_test", + "info_collection_tests", + "context_lost_validating_tests", + "depth_capture_tests", + "gpu_process_launch_tests" + ], + "chromeos-amd64-generic-rel-rts": [ + "telemetry_perf_unittests", + "webgl_conformance_tests" + ] +}
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4419e7b..aa0ab88 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -32642,6 +32642,7 @@ <int value="83" label="SharedAutofill"/> <int value="84" label="DirectSockets"/> <int value="85" label="ClientHintPrefersColorScheme"/> + <int value="86" label="WindowPlacement"/> </enum> <enum name="FeaturePolicyImageCompressionFormat">
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml index ee3ebb1..8be66ac4 100644 --- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -694,7 +694,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.CountDetectionAttempted" - units="count" expires_after="2021-08-09"> + units="count" expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -704,7 +704,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.CountLabelled" units="count" - expires_after="2021-08-09"> + expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -715,7 +715,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.LangsPerPage" units="count" - expires_after="2021-10-10"> + expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -727,7 +727,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageLabelledWithTop" - units="%" expires_after="2021-08-09"> + units="%" expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -739,7 +739,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageLanguageDetected" - units="%" expires_after="2021-05-23"> + units="%" expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner> @@ -750,7 +750,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageOverridden" - units="%" expires_after="2021-08-09"> + units="%" expires_after="2021-11-19"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml index 57b4e2d6..efa4894 100644 --- a/tools/metrics/histograms/histograms_xml/android/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -3260,9 +3260,13 @@ <histogram name="Android.WebView.ShouldInterceptRequest.NullInputStream.ResponseStatusCode" enum="HttpResponseCode" expires_after="2020-06-14"> + <obsolete> + Removed 2021-05 + </obsolete> <owner>timvolodine@chromium.org</owner> <owner>tobiasjs@chromium.org</owner> <owner>ntfschr@chromium.org</owner> + <owner>src/android_webview/OWNERS</owner> <summary> Records the custom response status code for the intercepted requests where input stream is null. In case status code is invalid (or has not been
diff --git a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml index ec46d6d..fcd6a66 100644 --- a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml
@@ -2139,6 +2139,7 @@ <histogram name="Autofill.UsedCachedServerCard" units="uses" expires_after="2021-12-20"> <owner>jsaul@google.com</owner> + <owner>siyua@chromium.org</owner> <owner>payments-autofill-team@google.com</owner> <summary> Records the number of times that the cache for unmasked server cards has @@ -2148,6 +2149,19 @@ </summary> </histogram> +<histogram name="Autofill.UsedCachedVirtualCard" units="uses" + expires_after="2021-12-20"> + <owner>jsaul@google.com</owner> + <owner>siyua@chromium.org</owner> + <owner>payments-autofill-team@google.com</owner> + <summary> + Records the number of times that the cache for virtual cards has been + accessed for a given card. For example, if the cache is being accessed and + it has already been accessed for the card twice before, then "3" + is recorded. + </summary> +</histogram> + <histogram name="Autofill.UserHappiness" enum="AutofillUserHappiness" expires_after="M95"> <owner>battre@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml index 55a63b5..1e72261 100644 --- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -28,8 +28,9 @@ </variants> <histogram name="Browser.AnyWindowHasName" enum="Boolean" - expires_after="2021-06-30"> + expires_after="2021-09-30"> <owner>ellyjones@chromium.org</owner> + <owner>lgrey@chromium.org</owner> <summary> Whether any browser window in the current session has a user-set name. Logged once every histogram recording.
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml index 9f5fa7a0..343b2cb 100644 --- a/tools/metrics/histograms/histograms_xml/download/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -228,7 +228,7 @@ </histogram> <histogram base="true" name="Download.InsecureBlocking.Extensions" - enum="InsecureDownloadExtensions" expires_after="M90"> + enum="InsecureDownloadExtensions" expires_after="M94"> <owner>jdeblasio@chromium.org</owner> <owner>estark@chromium.org</owner> <owner>cthomp@chromium.org</owner> @@ -239,7 +239,7 @@ </histogram> <histogram name="Download.InsecureBlocking.Totals" - enum="InsecureDownloadSecurityStatus" expires_after="M90"> + enum="InsecureDownloadSecurityStatus" expires_after="M94"> <owner>jdeblasio@chromium.org</owner> <owner>estark@chromium.org</owner> <owner>cthomp@chromium.org</owner> @@ -250,7 +250,7 @@ </histogram> <histogram base="true" name="Download.InsecureBlocking.Verification" - enum="DownloadContentType" expires_after="M90"> + enum="DownloadContentType" expires_after="M92"> <owner>jdeblasio@chromium.org</owner> <owner>estark@chromium.org</owner> <owner>cthomp@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml index 68355a5..d76b648 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -9047,6 +9047,8 @@ <suffix name="TextClassifier.FindLanguages" label=""/> <suffix name="TextClassifier.LoadModelResult" label=""/> <suffix name="TextClassifier.SuggestSelection" label=""/> + <suffix name="TextSuggester.LoadModelResult" label=""/> + <suffix name="TextSuggester.Suggest" label=""/> <affected-histogram name="MachineLearningService.CpuTimeMicrosec"/> <affected-histogram name="MachineLearningService.ElapsedTimeMicrosec"> <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/history/histograms.xml b/tools/metrics/histograms/histograms_xml/history/histograms.xml index b5fe2486..dc6dfb1 100644 --- a/tools/metrics/histograms/histograms_xml/history/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/history/histograms.xml
@@ -170,7 +170,7 @@ </histogram> <histogram name="History.ClearBrowsingData.FailedTasksChrome" - enum="ChromeBrowsingDataRemoverTasks" expires_after="2021-07-01"> + enum="ChromeBrowsingDataRemoverTasks" expires_after="2021-09-01"> <owner>dullweber@chromium.org</owner> <owner>msramek@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/mobile/OWNERS b/tools/metrics/histograms/histograms_xml/mobile/OWNERS new file mode 100644 index 0000000..bc7608b6c --- /dev/null +++ b/tools/metrics/histograms/histograms_xml/mobile/OWNERS
@@ -0,0 +1,5 @@ +per-file OWNERS=file://tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS + +# Prefer sending CLs to the owners listed below. +# Use chromium-metrics-reviews@google.com as a backup. +ender@chromium.org
diff --git a/tools/metrics/histograms/histograms_xml/nearby/histograms.xml b/tools/metrics/histograms/histograms_xml/nearby/histograms.xml index 7753cc8e..e93cb17 100644 --- a/tools/metrics/histograms/histograms_xml/nearby/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/nearby/histograms.xml
@@ -610,6 +610,18 @@ </summary> </histogram> +<histogram name="Nearby.Share.EnabledStateChanged" enum="BooleanEnabled" + expires_after="2021-10-25"> + <owner>nohle@chromium.org</owner> + <owner>nearby-share-chromeos-eng@google.com</owner> + <summary> + Records the enabled/disabled state of Nearby Share. Emitted when the feature + state changes from disabled to enabled or vice versa. This can happen after + Nearby Share onboarding or when the user enables/disables the Nearby Share + feature toggle in Settings. + </summary> +</histogram> + <histogram name="Nearby.Share.IsKnownContact" enum="BooleanKnown" expires_after="2021-10-25"> <owner>nohle@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 8b391a20..3d07e77 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -3545,6 +3545,17 @@ </summary> </histogram> +<histogram name="Conversions.Report.HttpResponseOrNetErrorCode" + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-10-17"> + <owner>johnidel@chromium.org</owner> + <owner>measurement-api-dev+metrics@google.com</owner> + <summary> + Error info for sending a conversion report, recorded for each sent report. + The HTTP response code is recorded if there is no net error code for the + request, or the net error code indicates there was a response code failusre. + </summary> +</histogram> + <histogram name="Conversions.ReportRetrySucceed" enum="BooleanSuccess" expires_after="M95"> <owner>johnidel@chromium.org</owner> @@ -9315,6 +9326,15 @@ </summary> </histogram> +<histogram name="MachineLearningService.TextSuggester.Suggest.Event" + enum="BooleanError" expires_after="2022-05-31"> + <owner>curtismcmullan@chromium.org</owner> + <owner>amoylan@chromium.org</owner> + <summary> + The result of a text suggester request, which can be OK or ERROR. + </summary> +</histogram> + <histogram base="true" name="MachineLearningService.TotalMemoryDeltaKb" units="KB" expires_after="2021-07-01"> <owner>amoylan@chromium.org</owner> @@ -14983,18 +15003,31 @@ </histogram> <histogram name="SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size" - units="origins" expires_after="2021-09-30"> + units="origins" expires_after="2021-11-30"> <owner>alexmos@chromium.org</owner> <owner>creis@chromium.org</owner> <owner>lukasza@chromium.org</owner> <summary> The number of currently saved user-triggered isolated sites. This includes sites where the user has entered a password while using Site Isolation for - password sites (which is the target Site Isolation mode for Android). + password sites (which is a currently active site isolation mode on Android). Recorded once on browser startup. </summary> </histogram> +<histogram name="SiteIsolation.SavedWebTriggeredIsolatedOrigins.Size" + units="origins" expires_after="2021-11-30"> + <owner>alexmos@chromium.org</owner> + <owner>creis@chromium.org</owner> + <owner>lukasza@chromium.org</owner> + <summary> + The number of currently saved web-triggered isolated sites. This includes + sites that were isolated due to Cross-Origin-Opener-Policy headers, which is + a heuristic used for site isolation on Android. Recorded once on browser + startup. + </summary> +</histogram> + <histogram name="SiteIsolation.SiteInstancesPerBrowsingInstance" units="units" expires_after="2021-09-30"> <owner>alexmos@chromium.org</owner> @@ -18427,7 +18460,7 @@ </histogram> <histogram name="Webapp.Update.ManifestUpdateResult.DefaultApp" - enum="WebAppManifestUpdateResult" expires_after="M92"> + enum="WebAppManifestUpdateResult" expires_after="M96"> <owner>alancutter@chromium.org</owner> <owner>tsergeant@chromium.org</owner> <owner>desktop-pwas-team@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml index 59f1c6f7..a0f0c47a 100644 --- a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
@@ -140,6 +140,9 @@ <histogram name="SBClientDownload.DownloadRequestPayloadSize" units="bytes" expires_after="M90"> + <obsolete> + Remove 05-2021 due to lack of use. + </obsolete> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <owner>mattm@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml index 08d0744..29fac3fd 100644 --- a/tools/metrics/histograms/histograms_xml/service/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -1123,7 +1123,7 @@ </histogram> <histogram name="ServiceWorker.Storage.RetryCountForRecovery" units="retries" - expires_after="2021-06-30"> + expires_after="2021-11-17"> <owner>bashi@chromium.org</owner> <owner>chrome-worker@google.com</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 7cab00a..1235a74 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,8 +1,8 @@ { "trace_processor_shell": { "win": { - "hash": "6c9d1659449dd8f1930cfcf263ab1005aa602320", - "remote_path": "perfetto_binaries/trace_processor_shell/win/5e860d49ed384a4785abec0eb68f4ce2f652dca6/trace_processor_shell.exe" + "hash": "d66c9ed761628a115d9b50ca0816aed0ff3155fa", + "remote_path": "perfetto_binaries/trace_processor_shell/win/eb6479ae08749f235840d15128127f39bc434ac1/trace_processor_shell.exe" }, "mac": { "hash": "b71e08180101b61191679d51b089504977d8c19c", @@ -10,7 +10,7 @@ }, "linux": { "hash": "9076c8b15696207c77b63956250bee3969d86d35", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/9109f50a742ab7b4cb70717308281137a8734b2b/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/linux/426cf86299ed21bd62ea2ba09af8ac27b69e02f1/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc index 722db1ee..57551faa 100644 --- a/ui/accessibility/accessibility_features.cc +++ b/ui/accessibility/accessibility_features.cc
@@ -161,4 +161,13 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_ANDROID) +const base::Feature kComputeAXMode{"ComputeAXMode", + base::FEATURE_DISABLED_BY_DEFAULT}; + +bool IsComputeAXModeEnabled() { + return base::FeatureList::IsEnabled(::features::kComputeAXMode); +} +#endif // defined(OS_ANDROID) + } // namespace features
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h index a303ecf..09e87f2 100644 --- a/ui/accessibility/accessibility_features.h +++ b/ui/accessibility/accessibility_features.h
@@ -147,6 +147,15 @@ AX_BASE_EXPORT bool IsSelectToSpeakNavigationControlEnabled(); #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if defined(OS_ANDROID) +// Compute the AXMode based on AccessibilityServiceInfo. If disabled, +// the AXMode is either entirely on or entirely off. +AX_BASE_EXPORT extern const base::Feature kComputeAXMode; + +// Returns true if the IChromeAccessible COM API is enabled. +AX_BASE_EXPORT bool IsComputeAXModeEnabled(); +#endif // defined(OS_ANDROID) + } // namespace features #endif // UI_ACCESSIBILITY_ACCESSIBILITY_FEATURES_H_
diff --git a/ui/base/x/BUILD.gn b/ui/base/x/BUILD.gn index 5f90ba68..5dc75c9 100644 --- a/ui/base/x/BUILD.gn +++ b/ui/base/x/BUILD.gn
@@ -16,6 +16,8 @@ "selection_requestor.h", "selection_utils.cc", "selection_utils.h", + "visual_picker_glx.cc", + "visual_picker_glx.h", "x11_clipboard_helper.cc", "x11_clipboard_helper.h", "x11_cursor.cc",
diff --git a/ui/gl/gl_visual_picker_glx.cc b/ui/base/x/visual_picker_glx.cc similarity index 74% rename from ui/gl/gl_visual_picker_glx.cc rename to ui/base/x/visual_picker_glx.cc index abe58bd..349598fd 100644 --- a/ui/gl/gl_visual_picker_glx.cc +++ b/ui/base/x/visual_picker_glx.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/gl/gl_visual_picker_glx.h" +#include "ui/base/x/visual_picker_glx.h" #include <algorithm> #include <bitset> @@ -13,11 +13,47 @@ #include "base/memory/singleton.h" #include "base/stl_util.h" #include "ui/gfx/x/future.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_surface_glx.h" -namespace gl { +// These constants are obtained from GL/glx.h and GL/glxext.h. +constexpr uint32_t GLX_LEVEL = 3; +constexpr uint32_t GLX_DOUBLEBUFFER = 5; +constexpr uint32_t GLX_STEREO = 6; +constexpr uint32_t GLX_BUFFER_SIZE = 2; +constexpr uint32_t GLX_AUX_BUFFERS = 7; +constexpr uint32_t GLX_RED_SIZE = 8; +constexpr uint32_t GLX_GREEN_SIZE = 9; +constexpr uint32_t GLX_BLUE_SIZE = 10; +constexpr uint32_t GLX_ALPHA_SIZE = 11; +constexpr uint32_t GLX_DEPTH_SIZE = 12; +constexpr uint32_t GLX_STENCIL_SIZE = 13; +constexpr uint32_t GLX_ACCUM_RED_SIZE = 14; +constexpr uint32_t GLX_ACCUM_GREEN_SIZE = 15; +constexpr uint32_t GLX_ACCUM_BLUE_SIZE = 16; +constexpr uint32_t GLX_ACCUM_ALPHA_SIZE = 17; + +constexpr uint32_t GLX_CONFIG_CAVEAT = 0x20; +constexpr uint32_t GLX_VISUAL_CAVEAT_EXT = 0x20; +constexpr uint32_t GLX_X_VISUAL_TYPE = 0x22; + +constexpr uint32_t GLX_BIND_TO_TEXTURE_TARGETS_EXT = 0x20D3; + +constexpr uint32_t GLX_NONE = 0x8000; +constexpr uint32_t GLX_NONE_EXT = 0x8000; +constexpr uint32_t GLX_TRUE_COLOR = 0x8002; +constexpr uint32_t GLX_VISUAL_ID = 0x800B; +constexpr uint32_t GLX_DRAWABLE_TYPE = 0x8010; +constexpr uint32_t GLX_RENDER_TYPE = 0x8011; +constexpr uint32_t GLX_FBCONFIG_ID = 0x8013; + +constexpr uint32_t GLX_PIXMAP_BIT = 0x00000002; +constexpr uint32_t GLX_TEXTURE_2D_BIT_EXT = 0x00000002; + +constexpr uint32_t GLX_SAMPLE_BUFFERS_ARB = 100000; +constexpr uint32_t GLX_SAMPLES = 100001; + +constexpr uint32_t GL_FALSE = 0; + +namespace ui { namespace { @@ -47,17 +83,19 @@ } // anonymous namespace // static -GLVisualPickerGLX* GLVisualPickerGLX::GetInstance() { - return base::Singleton<GLVisualPickerGLX>::get(); +VisualPickerGlx* VisualPickerGlx::GetInstance() { + return base::Singleton<VisualPickerGlx>::get(); } -x11::Glx::FbConfig GLVisualPickerGLX::GetFbConfigForFormat( - gfx::BufferFormat format) const { - auto it = config_map_.find(format); - return it == config_map_.end() ? x11::Glx::FbConfig{} : it->second; +x11::Glx::FbConfig VisualPickerGlx::GetFbConfigForFormat( + gfx::BufferFormat format) { + if (!config_map_) + FillConfigMap(); + auto it = config_map_->find(format); + return it == config_map_->end() ? x11::Glx::FbConfig{} : it->second; } -x11::VisualId GLVisualPickerGLX::PickBestGlVisual( +x11::VisualId VisualPickerGlx::PickBestGlVisual( const x11::Glx::GetVisualConfigsReply& configs, base::RepeatingCallback<bool(const x11::Connection::VisualInfo&)> pred, bool want_alpha) const { @@ -129,7 +167,7 @@ return best_visual; } -x11::VisualId GLVisualPickerGLX::PickBestSystemVisual( +x11::VisualId VisualPickerGlx::PickBestSystemVisual( const x11::Glx::GetVisualConfigsReply& configs) const { x11::Connection::VisualInfo default_visual_info = *connection_->GetVisualInfoFromId( @@ -154,7 +192,7 @@ IsArgbVisual(default_visual_info)); } -x11::VisualId GLVisualPickerGLX::PickBestRgbaVisual( +x11::VisualId VisualPickerGlx::PickBestRgbaVisual( const x11::Glx::GetVisualConfigsReply& configs) const { int best_class_score = -1; for (const auto& depth : connection_->default_screen().allowed_depths) { @@ -171,9 +209,10 @@ true); } -void GLVisualPickerGLX::FillConfigMap() { - if (!GLSurfaceGLX::HasGLXExtension("GLX_EXT_texture_from_pixmap")) - return; +void VisualPickerGlx::FillConfigMap() { + DCHECK(!config_map_); + config_map_ = + std::make_unique<base::flat_map<gfx::BufferFormat, x11::Glx::FbConfig>>(); if (auto configs = connection_->glx() .GetFBConfigs({connection_->DefaultScreenId()}) @@ -235,18 +274,18 @@ auto b = get(GLX_BLUE_SIZE); auto a = get(GLX_ALPHA_SIZE); if (r == 5 && g == 6 && b == 5 && a == 0) - config_map_[gfx::BufferFormat::BGR_565] = fbconfig; + (*config_map_)[gfx::BufferFormat::BGR_565] = fbconfig; else if (r == 8 && g == 8 && b == 8 && a == 0) - config_map_[gfx::BufferFormat::BGRX_8888] = fbconfig; + (*config_map_)[gfx::BufferFormat::BGRX_8888] = fbconfig; else if (r == 10 && g == 10 && b == 10 && a == 0) - config_map_[gfx::BufferFormat::BGRA_1010102] = fbconfig; + (*config_map_)[gfx::BufferFormat::BGRA_1010102] = fbconfig; else if (r == 8 && g == 8 && b == 8 && a == 8) - config_map_[gfx::BufferFormat::BGRA_8888] = fbconfig; + (*config_map_)[gfx::BufferFormat::BGRA_8888] = fbconfig; } } } -GLVisualPickerGLX::GLVisualPickerGLX() : connection_(x11::Connection::Get()) { +VisualPickerGlx::VisualPickerGlx() : connection_(x11::Connection::Get()) { auto configs = connection_->glx() .GetVisualConfigs({connection_->DefaultScreenId()}) .Sync(); @@ -255,10 +294,8 @@ system_visual_ = PickBestSystemVisual(*configs.reply); rgba_visual_ = PickBestRgbaVisual(*configs.reply); } - - FillConfigMap(); } -GLVisualPickerGLX::~GLVisualPickerGLX() = default; +VisualPickerGlx::~VisualPickerGlx() = default; -} // namespace gl +} // namespace ui
diff --git a/ui/gl/gl_visual_picker_glx.h b/ui/base/x/visual_picker_glx.h similarity index 71% rename from ui/gl/gl_visual_picker_glx.h rename to ui/base/x/visual_picker_glx.h index 5a48f9b..cd4772c 100644 --- a/ui/gl/gl_visual_picker_glx.h +++ b/ui/base/x/visual_picker_glx.h
@@ -2,43 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_GL_GL_VISUAL_PICKER_GLX_H_ -#define UI_GL_GL_VISUAL_PICKER_GLX_H_ +#ifndef UI_BASE_X_VISUAL_PICKER_GLX_H_ +#define UI_BASE_X_VISUAL_PICKER_GLX_H_ - +#include "base/component_export.h" #include "base/containers/flat_map.h" #include "base/macros.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/x/connection.h" #include "ui/gfx/x/glx.h" -#include "ui/gl/gl_export.h" namespace base { template <typename T> struct DefaultSingletonTraits; } -namespace gl { +namespace ui { // Picks the best X11 visuals to use for GL. This class is adapted from GTK's // pick_better_visual_for_gl. Tries to find visuals that // 1. Support GL // 2. Support double buffer // 3. Have an alpha channel only if we want one -class GL_EXPORT GLVisualPickerGLX { +class COMPONENT_EXPORT(UI_BASE_X) VisualPickerGlx { public: - static GLVisualPickerGLX* GetInstance(); + static VisualPickerGlx* GetInstance(); - ~GLVisualPickerGLX(); + ~VisualPickerGlx(); x11::VisualId system_visual() const { return system_visual_; } x11::VisualId rgba_visual() const { return rgba_visual_; } - x11::Glx::FbConfig GetFbConfigForFormat(gfx::BufferFormat format) const; + x11::Glx::FbConfig GetFbConfigForFormat(gfx::BufferFormat format); private: - friend struct base::DefaultSingletonTraits<GLVisualPickerGLX>; + friend struct base::DefaultSingletonTraits<VisualPickerGlx>; x11::VisualId PickBestGlVisual( const x11::Glx::GetVisualConfigsReply& configs, @@ -58,13 +57,14 @@ x11::VisualId system_visual_; x11::VisualId rgba_visual_; - base::flat_map<gfx::BufferFormat, x11::Glx::FbConfig> config_map_; + std::unique_ptr<base::flat_map<gfx::BufferFormat, x11::Glx::FbConfig>> + config_map_; - GLVisualPickerGLX(); + VisualPickerGlx(); - DISALLOW_COPY_AND_ASSIGN(GLVisualPickerGLX); + DISALLOW_COPY_AND_ASSIGN(VisualPickerGlx); }; -} // namespace gl +} // namespace ui -#endif // UI_GL_GL_VISUAL_PICKER_GLX_H_ +#endif // UI_BASE_X_VISUAL_PICKER_GLX_H_
diff --git a/ui/base/x/x11_gl_egl_utility.cc b/ui/base/x/x11_gl_egl_utility.cc index ae54288c..624c6f9 100644 --- a/ui/base/x/x11_gl_egl_utility.cc +++ b/ui/base/x/x11_gl_egl_utility.cc
@@ -39,20 +39,8 @@ void GetPlatformExtraDisplayAttribs(EGLenum platform_type, std::vector<EGLAttrib>* attributes) { - // ANGLE_NULL and SwiftShader backends don't use the visual, - // and may run without X11 where we can't get it anyway. - if ((platform_type != EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE) && - (std::find(attributes->begin(), attributes->end(), - EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE) == - attributes->end())) { - x11::VisualId visual_id; - XVisualManager::GetInstance()->ChooseVisualForWindow( - true, &visual_id, nullptr, nullptr, nullptr); - attributes->push_back(EGL_X11_VISUAL_ID_ANGLE); - attributes->push_back(static_cast<EGLAttrib>(visual_id)); - attributes->push_back(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE); - attributes->push_back(EGL_PLATFORM_X11_EXT); - } + attributes->push_back(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE); + attributes->push_back(EGL_PLATFORM_X11_EXT); } void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size, @@ -72,11 +60,4 @@ return ui::XVisualManager::GetInstance()->ArgbVisualAvailable(); } -bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - x11::VisualId default_visual_id, - x11::VisualId transparent_visual_id) { - return XVisualManager::GetInstance()->UpdateVisualsOnGpuInfoChanged( - software_rendering, default_visual_id, transparent_visual_id); -} - } // namespace ui
diff --git a/ui/base/x/x11_gl_egl_utility.h b/ui/base/x/x11_gl_egl_utility.h index fd33bbb..8f559f2 100644 --- a/ui/base/x/x11_gl_egl_utility.h +++ b/ui/base/x/x11_gl_egl_utility.h
@@ -8,7 +8,6 @@ #include <vector> #include "third_party/khronos/EGL/egl.h" -#include "ui/gfx/x/xproto.h" namespace ui { @@ -23,12 +22,6 @@ // Returns whether transparent background is suppored. bool IsTransparentBackgroundSupported(); -// Wraps XVisualManager::UpdateVisualsOnGpuInfoChanged(), passes parameters to -// it directly. Returns whether provided visuals are valid. -bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - x11::VisualId default_visual_id, - x11::VisualId transparent_visual_id); - } // namespace ui #endif // UI_BASE_X_X11_GL_EGL_UTILITY_H_
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index ff558ea..e96116b 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc
@@ -49,6 +49,7 @@ #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkTypes.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" +#include "ui/base/x/visual_picker_glx.h" #include "ui/base/x/x11_cursor.h" #include "ui/base/x/x11_cursor_loader.h" #include "ui/base/x/x11_menu_list.h" @@ -1006,14 +1007,10 @@ } bool DoesVisualHaveAlphaForTest() { - // testing/xvfb.py runs xvfb and xcompmgr. - std::unique_ptr<base::Environment> env(base::Environment::Create()); - uint8_t depth = 0; bool visual_has_alpha = false; ui::XVisualManager::GetInstance()->ChooseVisualForWindow( - env->HasVar("_CHROMIUM_INSIDE_XVFB"), nullptr, &depth, nullptr, - &visual_has_alpha); + true, nullptr, &depth, nullptr, &visual_has_alpha); if (visual_has_alpha) DCHECK_EQ(32, depth); @@ -1069,36 +1066,48 @@ return base::Singleton<XVisualManager>::get(); } -XVisualManager::XVisualManager() : connection_(x11::Connection::Get()) { - base::AutoLock lock(lock_); - - for (const auto& depth : connection_->default_screen().allowed_depths) { +XVisualManager::XVisualManager() { + auto* connection = x11::Connection::Get(); + for (const auto& depth : connection->default_screen().allowed_depths) { for (const auto& visual : depth.visuals) { visuals_[visual.visual_id] = - std::make_unique<XVisualData>(connection_, depth.depth, &visual); + std::make_unique<XVisualData>(connection, depth.depth, &visual); } } + auto* visual_picker = VisualPickerGlx::GetInstance(); + x11::ColorMap colormap; + // Choose the opaque visual. - default_visual_id_ = connection_->default_screen().root_visual; - system_visual_id_ = default_visual_id_; - DCHECK_NE(system_visual_id_, x11::VisualId{}); - DCHECK(visuals_.find(system_visual_id_) != visuals_.end()); + opaque_visual_id_ = visual_picker->system_visual(); + if (opaque_visual_id_ == x11::VisualId{}) + opaque_visual_id_ = connection->default_screen().root_visual; + // opaque_visual_id_ may be unset in headless environments + if (opaque_visual_id_ != x11::VisualId{}) { + DCHECK(visuals_.find(opaque_visual_id_) != visuals_.end()); + ChooseVisualForWindow(false, nullptr, nullptr, &colormap, nullptr); + } // Choose the transparent visual. - for (const auto& pair : visuals_) { - // Why support only 8888 ARGB? Because it's all that GTK+ supports. In - // gdkvisual-x11.cc, they look for this specific visual and use it for - // all their alpha channel using needs. - const auto& data = *pair.second; - if (data.depth == 32 && data.info->red_mask == 0xff0000 && - data.info->green_mask == 0x00ff00 && data.info->blue_mask == 0x0000ff) { - transparent_visual_id_ = pair.first; - break; + transparent_visual_id_ = visual_picker->rgba_visual(); + if (transparent_visual_id_ == x11::VisualId{}) { + for (const auto& pair : visuals_) { + // Why support only 8888 ARGB? Because it's all that GTK+ supports. In + // gdkvisual-x11.cc, they look for this specific visual and use it for + // all their alpha channel using needs. + const auto& data = *pair.second; + if (data.depth == 32 && data.info->red_mask == 0xff0000 && + data.info->green_mask == 0x00ff00 && + data.info->blue_mask == 0x0000ff) { + transparent_visual_id_ = pair.first; + break; + } } } - if (transparent_visual_id_ != x11::VisualId{}) + if (transparent_visual_id_ != x11::VisualId{}) { DCHECK(visuals_.find(transparent_visual_id_) != visuals_.end()); + ChooseVisualForWindow(true, nullptr, nullptr, &colormap, nullptr); + } } XVisualManager::~XVisualManager() = default; @@ -1108,16 +1117,12 @@ uint8_t* depth, x11::ColorMap* colormap, bool* visual_has_alpha) { - base::AutoLock lock(lock_); - bool use_argb = want_argb_visual && IsCompositingManagerPresent() && - (using_software_rendering_ || have_gpu_argb_visual_); - x11::VisualId visual = use_argb && transparent_visual_id_ != x11::VisualId{} - ? transparent_visual_id_ - : system_visual_id_; + bool use_argb = want_argb_visual && ArgbVisualAvailable(); + x11::VisualId visual = use_argb ? transparent_visual_id_ : opaque_visual_id_; if (visual_id) *visual_id = visual; - bool success = GetVisualInfoImpl(visual, depth, colormap, visual_has_alpha); + bool success = GetVisualInfo(visual, depth, colormap, visual_has_alpha); DCHECK(success); } @@ -1125,54 +1130,20 @@ uint8_t* depth, x11::ColorMap* colormap, bool* visual_has_alpha) { - base::AutoLock lock(lock_); - return GetVisualInfoImpl(visual_id, depth, colormap, visual_has_alpha); -} - -bool XVisualManager::UpdateVisualsOnGpuInfoChanged( - bool software_rendering, - x11::VisualId system_visual_id, - x11::VisualId transparent_visual_id) { - base::AutoLock lock(lock_); - // TODO(thomasanderson): Cache these visual IDs as a property of the root - // window so that newly created browser processes can get them immediately. - if ((system_visual_id != x11::VisualId{} && - !visuals_.count(system_visual_id)) || - (transparent_visual_id != x11::VisualId{} && - !visuals_.count(transparent_visual_id))) - return false; - using_software_rendering_ = software_rendering; - have_gpu_argb_visual_ = - have_gpu_argb_visual_ || transparent_visual_id != x11::VisualId{}; - if (system_visual_id != x11::VisualId{}) - system_visual_id_ = system_visual_id; - if (transparent_visual_id != x11::VisualId{}) - transparent_visual_id_ = transparent_visual_id; - return true; -} - -bool XVisualManager::ArgbVisualAvailable() const { - base::AutoLock lock(lock_); - return IsCompositingManagerPresent() && - (using_software_rendering_ || have_gpu_argb_visual_); -} - -bool XVisualManager::GetVisualInfoImpl(x11::VisualId visual_id, - uint8_t* depth, - x11::ColorMap* colormap, - bool* visual_has_alpha) { + DCHECK_NE(visual_id, x11::VisualId{}); auto it = visuals_.find(visual_id); if (it == visuals_.end()) return false; XVisualData& data = *it->second; const x11::VisualType& info = *data.info; - bool is_default_visual = visual_id == default_visual_id_; - if (depth) *depth = data.depth; - if (colormap) + if (colormap) { + bool is_default_visual = + visual_id == x11::Connection::Get()->default_root_visual().visual_id; *colormap = is_default_visual ? x11::ColorMap{} : data.GetColormap(); + } if (visual_has_alpha) { auto popcount = [](auto x) { return std::bitset<8 * sizeof(decltype(x))>(x).count(); @@ -1184,10 +1155,15 @@ return true; } +bool XVisualManager::ArgbVisualAvailable() const { + return IsCompositingManagerPresent() && + transparent_visual_id_ != x11::VisualId{}; +} + XVisualManager::XVisualData::XVisualData(x11::Connection* connection, uint8_t depth, const x11::VisualType* info) - : depth(depth), info(info), connection_(connection) {} + : depth(depth), info(info) {} // Do not free the colormap as this would uninstall the colormap even for // non-Chromium clients. @@ -1195,9 +1171,10 @@ x11::ColorMap XVisualManager::XVisualData::GetColormap() { if (colormap_ == x11::ColorMap{}) { - colormap_ = connection_->GenerateId<x11::ColorMap>(); - connection_->CreateColormap({x11::ColormapAlloc::None, colormap_, - connection_->default_root(), info->visual_id}); + auto* connection = x11::Connection::Get(); + colormap_ = connection->GenerateId<x11::ColorMap>(); + connection->CreateColormap({x11::ColormapAlloc::None, colormap_, + connection->default_root(), info->visual_id}); } return colormap_; }
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 14be4ae8..bf38c1fb 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h
@@ -40,7 +40,6 @@ namespace base { template <typename T> struct DefaultSingletonTraits; -class Value; } namespace gfx { @@ -378,13 +377,6 @@ // Suspends or resumes the X screen saver. Must be called on the UI thread. COMPONENT_EXPORT(UI_BASE_X) void SuspendX11ScreenSaver(bool suspend); -// Returns human readable description of the window manager, desktop, and -// other system properties related to the compositing. -COMPONENT_EXPORT(UI_BASE_X) -void StoreGpuExtraInfoIntoListValue(x11::VisualId system_visual, - x11::VisualId rgba_visual, - base::Value& list_value); - // Returns true if the window manager supports the given hint. COMPONENT_EXPORT(UI_BASE_X) bool WmSupportsHint(x11::Atom atom); @@ -412,8 +404,7 @@ // Return true if VulkanSurface is supported. COMPONENT_EXPORT(UI_BASE_X) bool IsVulkanSurfaceSupported(); -// Returns whether the visual supports alpha. -// The function examines the _CHROMIUM_INSIDE_XVFB environment variable. +// Returns whether ARGB visuals are supported. COMPONENT_EXPORT(UI_BASE_X) bool DoesVisualHaveAlphaForTest(); // Returns an icon for a native window referred by |target_window_id|. Can be @@ -440,14 +431,6 @@ x11::ColorMap* colormap, bool* visual_has_alpha); - // Called by GpuDataManagerImplPrivate when GPUInfo becomes available. It is - // necessary for the GPU process to find out which visuals are best for GL - // because we don't want to load GL in the browser process. Returns false iff - // |default_visual_id| or |transparent_visual_id| are invalid. - bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - x11::VisualId default_visual_id, - x11::VisualId transparent_visual_id); - // Are all of the system requirements met for using transparent visuals? bool ArgbVisualAvailable() const; @@ -470,32 +453,15 @@ private: x11::ColorMap colormap_{}; - x11::Connection* const connection_; }; XVisualManager(); - bool GetVisualInfoImpl(x11::VisualId visual_id, - uint8_t* depth, - x11::ColorMap* colormap, - bool* visual_has_alpha); - - mutable base::Lock lock_; - std::unordered_map<x11::VisualId, std::unique_ptr<XVisualData>> visuals_; - x11::Connection* const connection_; - - x11::VisualId default_visual_id_{}; - - // The system visual is usually the same as the default visual, but - // may not be in general. - x11::VisualId system_visual_id_{}; + x11::VisualId opaque_visual_id_{}; x11::VisualId transparent_visual_id_{}; - bool using_software_rendering_ = false; - bool have_gpu_argb_visual_ = false; - DISALLOW_COPY_AND_ASSIGN(XVisualManager); };
diff --git a/ui/gfx/gpu_extra_info.h b/ui/gfx/gpu_extra_info.h index 98234d2..c895145 100644 --- a/ui/gfx/gpu_extra_info.h +++ b/ui/gfx/gpu_extra_info.h
@@ -66,9 +66,6 @@ ANGLEFeatures angle_features; #if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) - x11::VisualId system_visual{}; - x11::VisualId rgba_visual{}; - std::vector<gfx::BufferUsageAndFormat> gpu_memory_buffer_support_x11; #endif };
diff --git a/ui/gfx/mojom/gpu_extra_info.mojom b/ui/gfx/mojom/gpu_extra_info.mojom index 705cc683..1b7b023 100644 --- a/ui/gfx/mojom/gpu_extra_info.mojom +++ b/ui/gfx/mojom/gpu_extra_info.mojom
@@ -23,9 +23,5 @@ array<ANGLEFeature> angle_features; [EnableIf=enable_x11_params] - uint64 system_visual; - [EnableIf=enable_x11_params] - uint64 rgba_visual; - [EnableIf=enable_x11_params] array<gfx.mojom.BufferUsageAndFormat> gpu_memory_buffer_support_x11; };
diff --git a/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc b/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc index 6b7ff134e..c40726b 100644 --- a/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc +++ b/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
@@ -25,14 +25,6 @@ if (!data.ReadAngleFeatures(&out->angle_features)) return false; #if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11) - // These visuals below are obtained via methods of gl::GLVisualPickerGLX class - // and consumed by ui::XVisualManager::UpdateVisualsOnGpuInfoChanged(); should - // bad visuals come there, the GPU process will be shut down. - // - // See content::GpuDataManagerVisualProxyOzoneLinux and the ShutdownGpuOnIO() - // function there. - out->system_visual = static_cast<x11::VisualId>(data.system_visual()); - out->rgba_visual = static_cast<x11::VisualId>(data.rgba_visual()); if (!data.ReadGpuMemoryBufferSupportX11(&out->gpu_memory_buffer_support_x11)) return false; #endif
diff --git a/ui/gfx/mojom/gpu_extra_info_mojom_traits.h b/ui/gfx/mojom/gpu_extra_info_mojom_traits.h index 40a1114c..dd6b118 100644 --- a/ui/gfx/mojom/gpu_extra_info_mojom_traits.h +++ b/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
@@ -62,14 +62,6 @@ } #if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11) - static uint64_t system_visual(const gfx::GpuExtraInfo& input) { - return static_cast<uint64_t>(input.system_visual); - } - - static uint64_t rgba_visual(const gfx::GpuExtraInfo& input) { - return static_cast<uint64_t>(input.rgba_visual); - } - static const std::vector<gfx::BufferUsageAndFormat>& gpu_memory_buffer_support_x11(const gfx::GpuExtraInfo& input) { return input.gpu_memory_buffer_support_x11;
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 2e5fff3..20e98943 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn
@@ -290,8 +290,6 @@ "gl_image_glx_native_pixmap.h", "gl_surface_glx.cc", "gl_surface_glx.h", - "gl_visual_picker_glx.cc", - "gl_visual_picker_glx.h", "glx_util.cc", "glx_util.h", ]
diff --git a/ui/gl/gl_image_egl_pixmap.cc b/ui/gl/gl_image_egl_pixmap.cc index 6c5612d..ac11b6d 100644 --- a/ui/gl/gl_image_egl_pixmap.cc +++ b/ui/gl/gl_image_egl_pixmap.cc
@@ -6,10 +6,10 @@ #include <memory> +#include "ui/gfx/x/connection.h" #include "ui/gl/buffer_format_utils.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_glx.h" -#include "ui/gl/gl_visual_picker_glx.h" namespace gl {
diff --git a/ui/gl/gl_image_glx.cc b/ui/gl/gl_image_glx.cc index 01f95ed..29d182e 100644 --- a/ui/gl/gl_image_glx.cc +++ b/ui/gl/gl_image_glx.cc
@@ -7,11 +7,11 @@ #include <memory> #include "base/logging.h" +#include "ui/base/x/visual_picker_glx.h" #include "ui/gl/buffer_format_utils.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_image_glx.h" #include "ui/gl/gl_surface_glx.h" -#include "ui/gl/gl_visual_picker_glx.h" #include "ui/gl/glx_util.h" namespace gl { @@ -46,7 +46,7 @@ bool GLImageGLX::Initialize(x11::Pixmap pixmap) { auto fbconfig_id = - GLVisualPickerGLX::GetInstance()->GetFbConfigForFormat(format_); + ui::VisualPickerGlx::GetInstance()->GetFbConfigForFormat(format_); auto* connection = x11::Connection::Get(); GLXFBConfig config = GetGlxFbConfigForXProtoFbConfig(connection, fbconfig_id);
diff --git a/ui/gl/gl_implementation.cc b/ui/gl/gl_implementation.cc index 5acbd036..3a1baf0d 100644 --- a/ui/gl/gl_implementation.cc +++ b/ui/gl/gl_implementation.cc
@@ -205,6 +205,19 @@ } } +void SetSoftwareWebGLCommandLineSwitches(base::CommandLine* command_line, + bool legacy_software_gl) { + if (legacy_software_gl) { + command_line->AppendSwitchASCII(switches::kUseGL, + kGLImplementationSwiftShaderForWebGLName); + } else { + command_line->AppendSwitchASCII(switches::kUseGL, + kGLImplementationANGLEName); + command_line->AppendSwitchASCII( + switches::kUseANGLE, kANGLEImplementationSwiftShaderForWebGLName); + } +} + const char* GetGLImplementationGLName(GLImplementationParts implementation) { for (auto name_pair : kGLImplementationNamePairs) { if (implementation.gl == name_pair.implementation.gl &&
diff --git a/ui/gl/gl_implementation.h b/ui/gl/gl_implementation.h index 2c34023..054d2c29 100644 --- a/ui/gl/gl_implementation.h +++ b/ui/gl/gl_implementation.h
@@ -140,6 +140,11 @@ GL_EXPORT void SetSoftwareGLCommandLineSwitches(base::CommandLine* command_line, bool legacy_software_gl); +// Set the software WebGL implementation on the provided command line +GL_EXPORT void SetSoftwareWebGLCommandLineSwitches( + base::CommandLine* command_line, + bool legacy_software_gl); + // Whether the implementation is one of the software GL implementations GL_EXPORT bool IsSoftwareGLImplementation(GLImplementationParts implementation);
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc index 6a8e253..1e40d49 100644 --- a/ui/gl/gl_surface_glx.cc +++ b/ui/gl/gl_surface_glx.cc
@@ -22,6 +22,7 @@ #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "ui/base/x/visual_picker_glx.h" #include "ui/base/x/x11_display_util.h" #include "ui/base/x/x11_util.h" #include "ui/base/x/x11_xrandr_interval_only_vsync_provider.h" @@ -32,7 +33,6 @@ #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface_presentation_helper.h" -#include "ui/gl/gl_visual_picker_glx.h" #include "ui/gl/glx_util.h" #include "ui/gl/sync_control_vsync_provider.h" @@ -437,7 +437,7 @@ return false; } - auto* visual_picker = gl::GLVisualPickerGLX::GetInstance(); + auto* visual_picker = ui::VisualPickerGlx::GetInstance(); auto visual_id = visual_picker->rgba_visual(); if (visual_id == x11::VisualId{}) visual_id = visual_picker->system_visual();
diff --git a/ui/gl/gl_utils.cc b/ui/gl/gl_utils.cc index 77d3d1a..70fa53a 100644 --- a/ui/gl/gl_utils.cc +++ b/ui/gl/gl_utils.cc
@@ -27,9 +27,10 @@ #endif #if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11) +#include "ui/base/x/visual_picker_glx.h" // nogncheck #include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" // nogncheck +#include "ui/gfx/x/glx.h" // nogncheck #include "ui/gl/gl_implementation.h" // nogncheck -#include "ui/gl/gl_visual_picker_glx.h" // nogncheck #endif namespace gl { @@ -163,12 +164,9 @@ } if (GetGLImplementation() == kGLImplementationDesktopGL) { - // Create the GLVisualPickerGLX singleton now while the GbmSupportX11 + // Create the VisualPickerGlx singleton now while the GbmSupportX11 // singleton is busy being created on another thread. - GLVisualPickerGLX* visual_picker = GLVisualPickerGLX::GetInstance(); - - info.system_visual = visual_picker->system_visual(); - info.rgba_visual = visual_picker->rgba_visual(); + auto* visual_picker = ui::VisualPickerGlx::GetInstance(); // With GLX, only BGR(A) buffer formats are supported. EGL does not have // this restriction.
diff --git a/ui/gtk/BUILD.gn b/ui/gtk/BUILD.gn index d83a802..7bdb5a0 100644 --- a/ui/gtk/BUILD.gn +++ b/ui/gtk/BUILD.gn
@@ -90,7 +90,6 @@ deps = [ ":gtk_stubs", "//base", - "//printing", "//skia", # GTK pulls pangoft2, which requires HarfBuzz symbols. When linking @@ -118,6 +117,10 @@ "//ui/views", ] + if (enable_basic_printing) { + deps += [ "//printing" ] + } + if (use_cups) { deps += [ "//printing/mojom" ] }
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc index dcfee840..38f049c 100644 --- a/ui/gtk/gtk_ui.cc +++ b/ui/gtk/gtk_ui.cc
@@ -22,7 +22,7 @@ #include "base/stl_util.h" #include "base/strings/string_split.h" #include "chrome/browser/themes/theme_properties.h" // nogncheck -#include "printing/buildflags/buildflags.h" +#include "printing/buildflags/buildflags.h" // nogncheck #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColor.h"
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc index 5e7dd30..62108f0 100644 --- a/ui/gtk/printing/print_dialog_gtk.cc +++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -33,7 +33,7 @@ #include "ui/gtk/printing/printing_gtk_util.h" #if defined(USE_CUPS) -#include "printing/mojom/print.mojom.h" +#include "printing/mojom/print.mojom.h" // nogncheck #endif using printing::PageRanges;
diff --git a/ui/ozone/platform/x11/gl_egl_utility_x11.cc b/ui/ozone/platform/x11/gl_egl_utility_x11.cc index d5612033..387e275 100644 --- a/ui/ozone/platform/x11/gl_egl_utility_x11.cc +++ b/ui/ozone/platform/x11/gl_egl_utility_x11.cc
@@ -42,13 +42,4 @@ return true; } -bool GLEGLUtilityX11::UpdateVisualsOnGpuInfoChanged( - bool software_rendering, - uint32_t default_visual_id, - uint32_t transparent_visual_id) { - return ui::UpdateVisualsOnGpuInfoChanged( - software_rendering, static_cast<x11::VisualId>(default_visual_id), - static_cast<x11::VisualId>(transparent_visual_id)); -} - } // namespace ui
diff --git a/ui/ozone/platform/x11/gl_egl_utility_x11.h b/ui/ozone/platform/x11/gl_egl_utility_x11.h index 1ca2ddf3..da5e2968 100644 --- a/ui/ozone/platform/x11/gl_egl_utility_x11.h +++ b/ui/ozone/platform/x11/gl_egl_utility_x11.h
@@ -28,9 +28,6 @@ gfx::GpuExtraInfo& gpu_extra_info) const override; bool X11DoesVisualHaveAlphaForTest() const override; bool HasVisualManager() override; - bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - uint32_t default_visual_id, - uint32_t transparent_visual_id) override; }; } // namespace ui
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.cc b/ui/ozone/platform/x11/x11_screen_ozone.cc index b17a53ae..7b3ab857 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone.cc +++ b/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -134,8 +134,6 @@ base::Value X11ScreenOzone::GetGpuExtraInfoAsListValue( const gfx::GpuExtraInfo& gpu_extra_info) { auto result = GetDesktopEnvironmentInfoAsListValue(); - StoreGpuExtraInfoIntoListValue(gpu_extra_info.system_visual, - gpu_extra_info.rgba_visual, result); StorePlatformNameIntoListValue(result, "x11"); return result; }
diff --git a/ui/ozone/public/platform_gl_egl_utility.cc b/ui/ozone/public/platform_gl_egl_utility.cc index 38a135e..756334b 100644 --- a/ui/ozone/public/platform_gl_egl_utility.cc +++ b/ui/ozone/public/platform_gl_egl_utility.cc
@@ -17,13 +17,4 @@ return false; } -bool PlatformGLEGLUtility::UpdateVisualsOnGpuInfoChanged( - bool software_rendering, - uint32_t default_visual_id, - uint32_t transparent_visual_id) { - NOTREACHED() << "This must not be called if the platform does not support " - "X11 visuals."; - return false; -} - } // namespace ui
diff --git a/ui/ozone/public/platform_gl_egl_utility.h b/ui/ozone/public/platform_gl_egl_utility.h index 34d79ac..59728da 100644 --- a/ui/ozone/public/platform_gl_egl_utility.h +++ b/ui/ozone/public/platform_gl_egl_utility.h
@@ -44,14 +44,6 @@ // X11 specific; returns whether the platform supports visuals. virtual bool HasVisualManager(); - - // X11 specific; sets new visuals. - // Must be called only if the X11 visual manager is available. - // Should be called when the updated GPU info is available. - // Returns whether the visuals provided were valid. - virtual bool UpdateVisualsOnGpuInfoChanged(bool software_rendering, - uint32_t default_visual_id, - uint32_t transparent_visual_id); }; } // namespace ui
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc index 4d8b7b7..ce480a8 100644 --- a/ui/platform_window/x11/x11_window.cc +++ b/ui/platform_window/x11/x11_window.cc
@@ -207,8 +207,7 @@ } void X11Window::Initialize(PlatformWindowInitProperties properties) { - PlatformWindowOpacity opacity = properties.opacity; - CreateXWindow(properties, opacity); + CreateXWindow(properties); // It can be a status icon window. If it fails to initialize, don't provide // it with a native window handle, close ourselves and let the client destroy @@ -400,10 +399,8 @@ if (properties.icon) SetWindowIcons(gfx::ImageSkia(), *properties.icon); - if (properties.type == PlatformWindowType::kDrag && - opacity == PlatformWindowOpacity::kTranslucentWindow) { + if (properties.type == PlatformWindowType::kDrag) SetOpacity(kDragWidgetOpacity); - } SetWmDragHandler(this, this); @@ -961,10 +958,13 @@ } bool X11Window::IsTranslucentWindowOpacitySupported() const { - // This function may be called before InitX11Window() (which - // initializes |visual_has_alpha_|), so we cannot simply return - // |visual_has_alpha_|. - return ui::XVisualManager::GetInstance()->ArgbVisualAvailable(); + // If this function may be called before InitX11Window() (which + // initializes |visual_has_alpha_|), return whether it is possible + // to create windows with ARGB visuals. + if (xwindow_ == x11::Window::None) + ui::XVisualManager::GetInstance()->ArgbVisualAvailable(); + + return visual_has_alpha_; } void X11Window::SetOpacity(float opacity) { @@ -1519,19 +1519,13 @@ located_event); } -void X11Window::CreateXWindow(const PlatformWindowInitProperties& properties, - PlatformWindowOpacity& opacity) { +void X11Window::CreateXWindow(const PlatformWindowInitProperties& properties) { auto bounds = properties.bounds; gfx::Size adjusted_size_in_pixels = AdjustSizeForDisplay(bounds.size()); bounds.set_size(adjusted_size_in_pixels); const auto override_redirect = properties.x11_extension_delegate && properties.x11_extension_delegate->IsOverrideRedirect(IsWmTiling()); - if (properties.type == PlatformWindowType::kDrag) { - opacity = ui::IsCompositingManagerPresent() - ? PlatformWindowOpacity::kTranslucentWindow - : PlatformWindowOpacity::kOpaqueWindow; - } workspace_extension_delegate_ = properties.workspace_extension_delegate; x11_extension_delegate_ = properties.x11_extension_delegate; @@ -1575,7 +1569,7 @@ override_redirect_ = req.override_redirect.has_value(); bool enable_transparent_visuals; - switch (opacity) { + switch (properties.opacity) { case PlatformWindowOpacity::kOpaqueWindow: enable_transparent_visuals = false; break;
diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h index dbaf7eba..b8b98f0b 100644 --- a/ui/platform_window/x11/x11_window.h +++ b/ui/platform_window/x11/x11_window.h
@@ -220,8 +220,7 @@ // Depending on presence of the compositing manager and window type, may // change the opacity, in which case returns the final opacity type through // |opacity|. - void CreateXWindow(const PlatformWindowInitProperties& properties, - PlatformWindowOpacity& opacity); + void CreateXWindow(const PlatformWindowInitProperties& properties); void CloseXWindow(); void Map(bool inactive = false); void SetFullscreen(bool fullscreen);
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc index 4faed83e..956c0824 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -163,14 +163,6 @@ return x11_display_manager_->GetCurrentWorkspace(); } -base::Value DesktopScreenX11::GetGpuExtraInfoAsListValue( - const gfx::GpuExtraInfo& gpu_extra_info) { - auto result = ui::GetDesktopEnvironmentInfoAsListValue(); - ui::StoreGpuExtraInfoIntoListValue(gpu_extra_info.system_visual, - gpu_extra_info.rgba_visual, result); - return result; -} - void DesktopScreenX11::OnEvent(const x11::Event& event) { x11_display_manager_->OnEvent(event); }
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.h b/ui/views/widget/desktop_aura/desktop_screen_x11.h index dd7725c..efbb849 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_x11.h +++ b/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -53,8 +53,6 @@ void AddObserver(display::DisplayObserver* observer) override; void RemoveObserver(display::DisplayObserver* observer) override; std::string GetCurrentWorkspace() override; - base::Value GetGpuExtraInfoAsListValue( - const gfx::GpuExtraInfo& gpu_extra_info) override; // x11::EventObserver: void OnEvent(const x11::Event& event) override;
diff --git a/ui/views/widget/native_widget_mac_interactive_uitest.mm b/ui/views/widget/native_widget_mac_interactive_uitest.mm index 77a8c22..e28d988 100644 --- a/ui/views/widget/native_widget_mac_interactive_uitest.mm +++ b/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -14,6 +14,7 @@ #import "ui/events/test/cocoa_test_event_utils.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/controls/textfield/textfield.h" +#include "ui/views/test/native_widget_factory.h" #include "ui/views/test/test_widget_observer.h" #include "ui/views/test/widget_test.h" @@ -248,6 +249,41 @@ parent_widget->CloseNow(); } +// Test activation of a window that has restoration data that was restored to +// the dock. See crbug.com/1205683 . +TEST_F(NativeWidgetMacInteractiveUITest, + DeminiaturizeWindowWithRestorationData) { + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.native_widget = + CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr); + // Start the window off in the dock. + params.show_state = ui::SHOW_STATE_MINIMIZED; + // "{}" in base64encode, to create some dummy restoration data. + const std::string kDummyWindowRestorationData = "e30="; + params.workspace = kDummyWindowRestorationData; + widget->Init(std::move(params)); + + NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow(); + EXPECT_TRUE([window isMiniaturized]); + + // As part of the window restoration process, + // SessionRestoreImpl::ShowBrowser() -> BrowserView::Show() -> + // views::Widget::Show() -> views::NativeWidgetMac::Show() which calls + // SetVisibilityState(), the code path we want to test. Even though the method + // name is Show(), it "shows" the saved_show_state_ which in this case is + // WindowVisibilityState::kHideWindow. + widget->Show(); + EXPECT_TRUE([window isMiniaturized]); + + // Activate the window from the dock (i.e. + // SetVisibilityState(WindowVisibilityState::kShowAndActivateWindow)). + widget->Activate(); + EXPECT_FALSE([window isMiniaturized]); + + widget->CloseNow(); +} + // Test that bubble widgets are dismissed on right mouse down. TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) { Widget* parent_widget = CreateTopLevelPlatformWidget();
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm index 6ad0a5fe..866fb8bb 100644 --- a/ui/views/widget/native_widget_mac_unittest.mm +++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -46,6 +46,11 @@ #include "ui/views/widget/native_widget_private.h" #include "ui/views/window/dialog_delegate.h" +namespace { +// "{}" in base64encode, to create some dummy restoration data. +const std::string kDummyWindowRestorationData = "e30="; +} // namespace + // Donates an implementation of -[NSAnimation stopAnimation] which calls the // original implementation, then quits a nested run loop. @interface TestStopAnimationWaiter : NSObject @@ -110,6 +115,10 @@ bridge_->show_animation_.get()); } + bool HasWindowRestorationData() { + return bridge_->HasWindowRestorationData(); + } + private: remote_cocoa::NativeWidgetNSWindowBridge* bridge_; @@ -1174,6 +1183,55 @@ } } +// Tests that the first call into SetVisibilityState() restores the window state +// for windows that start off miniaturized in the dock. +TEST_F(NativeWidgetMacTest, ConfirmMinimizedWindowRestoration) { + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.native_widget = + CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr); + // Start the window off in the dock. + params.show_state = ui::SHOW_STATE_MINIMIZED; + params.workspace = kDummyWindowRestorationData; + widget->Init(std::move(params)); + + BridgedNativeWidgetTestApi test_api( + widget->GetNativeWindow().GetNativeNSWindow()); + + EXPECT_TRUE(test_api.HasWindowRestorationData()); + + // Show() ultimately invokes SetVisibilityState(). + widget->Show(); + + EXPECT_FALSE(test_api.HasWindowRestorationData()); + + widget->CloseNow(); +} + +// Tests that the first call into SetVisibilityState() restores the window state +// for windows that start off visible. +TEST_F(NativeWidgetMacTest, ConfirmVisibleWindowRestoration) { + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.native_widget = + CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr); + params.show_state = ui::SHOW_STATE_NORMAL; + params.workspace = kDummyWindowRestorationData; + widget->Init(std::move(params)); + + BridgedNativeWidgetTestApi test_api( + widget->GetNativeWindow().GetNativeNSWindow()); + + EXPECT_TRUE(test_api.HasWindowRestorationData()); + + // Show() ultimately invokes SetVisibilityState(). + widget->Show(); + + EXPECT_FALSE(test_api.HasWindowRestorationData()); + + widget->CloseNow(); +} + // Tests that calls to Hide() a Widget cancel any in-progress show animation, // and that clients can control the triggering of the animation. TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index 01a65c8..429f72b0 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc
@@ -4062,6 +4062,18 @@ #endif } +bool ExpectWidgetTransparency(Widget::InitParams::WindowOpacity opacity) { + switch (opacity) { + case Widget::InitParams::WindowOpacity::kOpaque: + return false; + case Widget::InitParams::WindowOpacity::kTranslucent: + return true; + case Widget::InitParams::WindowOpacity::kInferred: + ADD_FAILURE() << "WidgetOpacity must be explicitly set"; + return false; + } +} + class CompositingWidgetTest : public DesktopWidgetTest { public: CompositingWidgetTest() @@ -4118,13 +4130,10 @@ should_be_transparent); if (CanHaveCompositingManager()) { - if (HasCompositingManager() && - (widget_type == Widget::InitParams::TYPE_DRAG || - widget_type == Widget::InitParams::TYPE_WINDOW)) { + if (HasCompositingManager() && ExpectWidgetTransparency(opacity)) EXPECT_TRUE(widget->IsTranslucentWindowOpacitySupported()); - } else { + else EXPECT_FALSE(widget->IsTranslucentWindowOpacitySupported()); - } } } } @@ -4139,11 +4148,8 @@ } // namespace -// Test opacity when compositing is enabled. -TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetInferOpacity) { - CheckAllWidgetsForOpacity(Widget::InitParams::WindowOpacity::kInferred); -} - +// Only test manually set opacity via kOpaque or kTranslucent. kInferred is +// unpredictable and depends on the platform and window type. TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetOpaque) { CheckAllWidgetsForOpacity(Widget::InitParams::WindowOpacity::kOpaque); }
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn index 803d3247..620d18b 100644 --- a/ui/webui/resources/BUILD.gn +++ b/ui/webui/resources/BUILD.gn
@@ -143,7 +143,10 @@ "cr_elements/cr_drawer/cr_drawer.d.ts", "cr_elements/cr_icon_button/cr_icon_button.m.d.ts", "cr_elements/cr_input/cr_input.m.d.ts", + "cr_elements/cr_lazy_render/cr_lazy_render.m.d.ts", + "cr_elements/cr_search_field/cr_search_field_behavior.d.ts", "cr_elements/cr_toast/cr_toast.m.d.ts", + "cr_elements/cr_toolbar/cr_toolbar_search_field.d.ts", "cr_elements/cr_view_manager/cr_view_manager.d.ts", "cr_elements/find_shortcut_behavior.d.ts", "js/cr/ui/focus_row_behavior.m.d.ts", @@ -180,6 +183,7 @@ "$root_dir/cr_elements/cr_input/cr_input_style_css.m.d.ts", "$root_dir/cr_elements/cr_menu_selector/cr_menu_selector.d.ts", "$root_dir/cr_elements/cr_splitter/cr_splitter.d.ts", + "$root_dir/cr_elements/cr_toolbar/cr_toolbar.d.ts", "$root_dir/cr_elements/hidden_style_css.m.d.ts", "$root_dir/cr_elements/icons.m.d.ts", "$root_dir/cr_elements/md_select_css.m.d.ts", @@ -191,6 +195,8 @@ "$root_dir/js/cr/ui/focus_grid.m.d.ts", "$root_dir/js/cr/ui/focus_outline_manager.m.d.ts", "$root_dir/js/cr/ui/focus_row.m.d.ts", + "$root_dir/js/cr/ui/store.m.d.ts", + "$root_dir/js/cr/ui/store_client.m.d.ts", "$root_dir/js/event_tracker.m.d.ts", "$root_dir/js/load_time_data.m.d.ts", "$root_dir/js/parse_html_subset.m.d.ts", @@ -219,6 +225,7 @@ "cr_elements/cr_input/cr_input_style_css.m.js", "cr_elements/cr_menu_selector/cr_menu_selector.js", "cr_elements/cr_splitter/cr_splitter.js", + "cr_elements/cr_toolbar/cr_toolbar.js", "cr_elements/hidden_style_css.m.js", "cr_elements/icons.m.js", "cr_elements/md_select_css.m.js", @@ -229,6 +236,8 @@ "js/cr/event_target.m.js", "js/cr/ui/focus_grid.m.js", "js/cr/ui/focus_outline_manager.m.js", + "js/cr/ui/store.m.js", + "js/cr/ui/store_client.m.js", "js/cr/ui/focus_row.m.js", "js/event_tracker.m.js", "js/load_time_data.m.js",
diff --git a/ui/webui/resources/cr_components/BUILD.gn b/ui/webui/resources/cr_components/BUILD.gn index e1ab44f6..5cb6265 100644 --- a/ui/webui/resources/cr_components/BUILD.gn +++ b/ui/webui/resources/cr_components/BUILD.gn
@@ -148,6 +148,7 @@ in_files += [ "chromeos/bluetooth/bluetooth_dialog.m.js", "chromeos/cellular_setup/activation_code_page.m.js", + "chromeos/cellular_setup/activation_verification_page.m.js", "chromeos/cellular_setup/base_page.m.js", "chromeos/cellular_setup/button_bar.m.js", "chromeos/cellular_setup/cellular_setup_delegate.m.js", @@ -275,6 +276,8 @@ in_files += [ "chromeos/cellular_setup/activation_code_page.html", "chromeos/cellular_setup/activation_code_page.js", + "chromeos/cellular_setup/activation_verification_page.html", + "chromeos/cellular_setup/activation_verification_page.js", "chromeos/cellular_setup/base_page.html", "chromeos/cellular_setup/base_page.js", "chromeos/cellular_setup/button_bar.html",
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn index 31776a0..ea45ec53 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn
@@ -13,6 +13,7 @@ is_polymer3 = true deps = [ ":activation_code_page.m", + ":activation_verification_page.m", ":base_page.m", ":button_bar.m", ":cellular_eid_dialog.m", @@ -54,6 +55,17 @@ extra_deps = [ ":final_page_module" ] } +js_library("activation_verification_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.m.js" ] + deps = [ + ":base_page.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m", + "//ui/webui/resources/js:i18n_behavior.m", + ] + extra_deps = [ ":activation_verification_page_module" ] +} + js_library("activation_code_page.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.m.js" ] deps = [ @@ -201,6 +213,7 @@ sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.m.js" ] deps = [ ":activation_code_page.m", + ":activation_verification_page.m", ":cellular_setup_delegate.m", ":cellular_types.m", ":confirmation_code_page.m", @@ -245,6 +258,7 @@ group("polymer3_elements") { public_deps = [ ":activation_code_page_module", + ":activation_verification_page_module", ":base_page_module", ":button_bar_module", ":cellular_eid_dialog_module", @@ -278,6 +292,14 @@ auto_imports = cr_components_chromeos_auto_imports } +polymer_modulizer("activation_verification_page") { + js_file = "activation_verification_page.js" + html_file = "activation_verification_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + polymer_modulizer("activation_code_page") { js_file = "activation_code_page.js" html_file = "activation_code_page.html"
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.html new file mode 100644 index 0000000..9930ca1c --- /dev/null +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.html
@@ -0,0 +1,36 @@ +<link rel="import" href="../../../html/polymer.html"> + +<link rel="import" href="base_page.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html"> + +<dom-module id="activation-verification-page"> + <template> + <style> + #pageBody { + height: 282px; + margin-top: -20px; + overflow: hidden; + } + + #animationContainer { + display: flex; + height: 216px; + margin-bottom: 30px; + margin-top: 24px; + } + </style> + + <base-page> + <div slot="page-body" id="pageBody" class="layout vertical center-center"> + <span>[[i18n('verifyingActivationCode')]]</span> + <div id="animationContainer"> + <cr-lottie id="spinner" animation-url="spinner.json" autoplay> + </cr-lottie> + </div> + </div> + </base-page> + </template> + <script src="activation_verification_page.js"></script> +</dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.js new file mode 100644 index 0000000..5868da10 --- /dev/null +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_verification_page.js
@@ -0,0 +1,13 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This page is displayed when the activation code is being verified, and + * an ESim profile is being installed. + */ +Polymer({ + is: 'activation-verification-page', + + behaviors: [I18nBehavior], +});
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html index edc972a..916383a9 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html
@@ -12,6 +12,7 @@ <link rel="import" href="cellular_setup_delegate.html"> <link rel="import" href="setup_loading_page.html"> <link rel="import" href="activation_code_page.html"> +<link rel="import" href="activation_verification_page.html"> <link rel="import" href="final_page.html"> <link rel="import" href="profile_discovery_list_page.html"> <link rel="import" href="confirmation_code_page.html"> @@ -43,6 +44,8 @@ show-error="{{showError_}}" show-busy="[[shouldShowSubpageBusy_(state_)]]"> </activation-code-page> + <activation-verification-page id="activationVerificationPage"> + </activation-verification-page> <confirmation-code-page id="confirmationCodePage" confirmation-code="{{confirmationCode_}}" profile="[[selectedProfile_]]"
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js index 215120b..ee35f8f 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js
@@ -8,6 +8,7 @@ PROFILE_LOADING: 'profileLoadingPage', PROFILE_DISCOVERY: 'profileDiscoveryPage', ACTIVATION_CODE: 'activationCodePage', + ACTIVATION_VERIFCATION: 'activationVerificationPage', CONFIRMATION_CODE: 'confirmationCodePage', FINAL: 'finalPage', }; @@ -364,9 +365,11 @@ break; case ESimUiState.ACTIVATION_CODE_ENTRY: case ESimUiState.ACTIVATION_CODE_ENTRY_READY: - case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING: this.selectedESimPageName_ = ESimPageName.ACTIVATION_CODE; break; + case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING: + this.selectedESimPageName_ = ESimPageName.ACTIVATION_VERIFCATION; + break; case ESimUiState.CONFIRMATION_CODE_ENTRY: case ESimUiState.CONFIRMATION_CODE_ENTRY_READY: case ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING:
diff --git a/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.m.d.ts b/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.m.d.ts new file mode 100644 index 0000000..7f9abac --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.m.d.ts
@@ -0,0 +1,18 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {LegacyElementMixin} from 'chrome://resources/polymer/v3_0/polymer/lib/legacy/legacy-element-mixin.js'; + +interface CrLazyRenderElement extends LegacyElementMixin, HTMLElement { + get(): Element; + getIfExists(): (Element|null); +} + +export {CrLazyRenderElement}; + +declare global { + interface HTMLElementTagNameMap { + 'cr-lazy-render': CrLazyRenderElement; + } +}
diff --git a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.d.ts b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.d.ts new file mode 100644 index 0000000..291713ad --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.d.ts
@@ -0,0 +1,20 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export interface CrSearchFieldBehaviorInterface { + label: string; + clearLabel: string; + hasSearchText: boolean; + getSearchInput(): HTMLInputElement; + getValue(): string; + setValue(value: string, noEvent?: boolean): void; + onSearchTermSearch(): void; + onSearchTermInput(): void; +} + +export {CrSearchFieldBehavior}; + +interface CrSearchFieldBehavior extends CrSearchFieldBehaviorInterface {} + +declare const CrSearchFieldBehavior: object;
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js index 98d4d1f..46f862f 100644 --- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js +++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js
@@ -4,82 +4,90 @@ import '../cr_icon_button/cr_icon_button.m.js'; import '../cr_icons_css.m.js'; -import './cr_toolbar_search_field.js'; import '../hidden_style_css.m.js'; import '../icons.m.js'; import '../shared_vars_css.m.js'; import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js'; -import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -Polymer({ - is: 'cr-toolbar', +import {CrToolbarSearchFieldElement} from './cr_toolbar_search_field.js'; - _template: html`{__html_template__}`, +export class CrToolbarElement extends PolymerElement { + static get is() { + return 'cr-toolbar'; + } - properties: { - // Name to display in the toolbar, in titlecase. - pageName: String, + static get template() { + return html`{__html_template__}`; + } - // Prompt text to display in the search field. - searchPrompt: String, + static get properties() { + return { + // Name to display in the toolbar, in titlecase. + pageName: String, - // Tooltip to display on the clear search button. - clearLabel: String, + // Prompt text to display in the search field. + searchPrompt: String, - // Tooltip to display on the menu button. - menuLabel: String, + // Tooltip to display on the clear search button. + clearLabel: String, - // Value is proxied through to cr-toolbar-search-field. When true, - // the search field will show a processing spinner. - spinnerActive: Boolean, + // Tooltip to display on the menu button. + menuLabel: String, - // Controls whether the menu button is shown at the start of the menu. - showMenu: {type: Boolean, value: false}, + // Value is proxied through to cr-toolbar-search-field. When true, + // the search field will show a processing spinner. + spinnerActive: Boolean, - // Controls whether the search field is shown. - showSearch: {type: Boolean, value: true}, + // Controls whether the menu button is shown at the start of the menu. + showMenu: {type: Boolean, value: false}, - // Controls whether the search field is autofocused. - autofocus: { - type: Boolean, - value: false, - reflectToAttribute: true, - }, + // Controls whether the search field is shown. + showSearch: {type: Boolean, value: true}, - // True when the toolbar is displaying in narrow mode. - narrow: { - type: Boolean, - reflectToAttribute: true, - readonly: true, - notify: true, - }, + // Controls whether the search field is autofocused. + autofocus: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, - /** - * The threshold at which the toolbar will change from normal to narrow - * mode, in px. - */ - narrowThreshold: { - type: Number, - value: 900, - }, + // True when the toolbar is displaying in narrow mode. + narrow: { + type: Boolean, + reflectToAttribute: true, + readonly: true, + notify: true, + }, - /** @private */ - showingSearch_: { - type: Boolean, - reflectToAttribute: true, - }, - }, + /** + * The threshold at which the toolbar will change from normal to narrow + * mode, in px. + */ + narrowThreshold: { + type: Number, + value: 900, + }, + + /** @private */ + showingSearch_: { + type: Boolean, + reflectToAttribute: true, + }, + }; + } /** @return {!CrToolbarSearchFieldElement} */ getSearchField() { return /** @type {!CrToolbarSearchFieldElement} */ (this.$.search); - }, + } /** @private */ onMenuTap_() { - this.fire('cr-toolbar-menu-tap'); - }, + this.dispatchEvent(new CustomEvent( + 'cr-toolbar-menu-tap', {bubbles: true, composed: true})); + } focusMenuButton() { requestAnimationFrame(() => { @@ -90,11 +98,13 @@ menuButton.focus(); } }); - }, + } /** @return {boolean} */ isMenuFocused() { return Boolean(this.shadowRoot.activeElement) && this.shadowRoot.activeElement.id === 'menuButton'; } -}); +} + +customElements.define(CrToolbarElement.is, CrToolbarElement);
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.d.ts b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.d.ts new file mode 100644 index 0000000..e619a79 --- /dev/null +++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.d.ts
@@ -0,0 +1,30 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {LegacyElementMixin} from 'chrome://resources/polymer/v3_0/polymer/lib/legacy/legacy-element-mixin.js'; + +import {CrSearchFieldBehaviorInterface} from '../cr_search_field/cr_search_field_behavior.js'; + +interface CrToolbarSearchFieldElement extends CrSearchFieldBehaviorInterface, + LegacyElementMixin, HTMLElement { + narrow: boolean; + showingSearch: boolean; + autofocus: boolean; + label: string; + clearLabel: string; + spinnerActive: boolean; + + getSearchInput(): HTMLInputElement; + isSearchFocused(): boolean; + showAndFocus(): void; + onSearchTermInput(): void; +} + +export {CrToolbarSearchFieldElement}; + +declare global { + interface HTMLElementTagNameMap { + 'cr-toolbar-search-field': CrToolbarSearchFieldElement; + } +}
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js index 47be44f..15dd22e2 100644 --- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js +++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js
@@ -9,91 +9,108 @@ import '../shared_vars_css.m.js'; import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; -import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {html, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {CrSearchFieldBehavior} from '../cr_search_field/cr_search_field_behavior.js'; +import {CrSearchFieldBehavior, CrSearchFieldBehaviorInterface} from '../cr_search_field/cr_search_field_behavior.js'; -Polymer({ - is: 'cr-toolbar-search-field', +/** + * @constructor + * @extends {PolymerElement} + * @implements {CrSearchFieldBehaviorInterface} + */ +const CrToolbarSearchFieldElementBase = + mixinBehaviors(CrSearchFieldBehavior, PolymerElement); - _template: html`{__html_template__}`, +/** @polymer */ +export class CrToolbarSearchFieldElement extends + CrToolbarSearchFieldElementBase { + static get is() { + return 'cr-toolbar-search-field'; + } - behaviors: [CrSearchFieldBehavior], + static get template() { + return html`{__html_template__}`; + } - properties: { - narrow: { - type: Boolean, - reflectToAttribute: true, - }, + static get properties() { + return { + narrow: { + type: Boolean, + reflectToAttribute: true, + }, - showingSearch: { - type: Boolean, - value: false, - notify: true, - observer: 'showingSearchChanged_', - reflectToAttribute: true - }, + showingSearch: { + type: Boolean, + value: false, + notify: true, + observer: 'showingSearchChanged_', + reflectToAttribute: true, + }, - autofocus: { - type: Boolean, - value: false, - reflectToAttribute: true, - }, + autofocus: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, - // Prompt text to display in the search field. - label: String, + // Prompt text to display in the search field. + label: String, - // Tooltip to display on the clear search button. - clearLabel: String, + // Tooltip to display on the clear search button. + clearLabel: String, - // When true, show a loading spinner to indicate that the backend is - // processing the search. Will only show if the search field is open. - spinnerActive: {type: Boolean, reflectToAttribute: true}, + // When true, show a loading spinner to indicate that the backend is + // processing the search. Will only show if the search field is open. + spinnerActive: {type: Boolean, reflectToAttribute: true}, - /** @private */ - isSpinnerShown_: { - type: Boolean, - computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)' - }, + /** @private */ + isSpinnerShown_: { + type: Boolean, + computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)' + }, - /** @private */ - searchFocused_: {type: Boolean, value: false}, - }, + /** @private */ + searchFocused_: {type: Boolean, value: false}, + }; + } - listeners: { - // Deliberately uses 'click' instead of 'tap' to fix crbug.com/624356. - 'click': 'showSearch_', - }, + /** @override */ + ready() { + super.ready(); + + this.addEventListener('click', e => this.showSearch_(e)); + } /** @return {!HTMLInputElement} */ getSearchInput() { return /** @type {!HTMLInputElement} */ (this.$.searchInput); - }, + } /** @return {boolean} */ isSearchFocused() { return this.searchFocused_; - }, + } showAndFocus() { this.showingSearch = true; this.focus_(); - }, + } onSearchTermInput() { CrSearchFieldBehavior.onSearchTermInput.call(this); this.showingSearch = this.hasSearchText || this.isSearchFocused(); - }, + } /** @private */ onSearchIconClicked_() { - this.fire('search-icon-clicked'); - }, + this.dispatchEvent(new CustomEvent( + 'search-icon-clicked', {bubbles: true, composed: true})); + } /** @private */ focus_() { this.getSearchInput().focus(); - }, + } /** * @param {boolean} narrow @@ -102,7 +119,7 @@ */ computeIconTabIndex_(narrow) { return narrow && !this.hasSearchText ? 0 : -1; - }, + } /** * @param {boolean} narrow @@ -111,7 +128,7 @@ */ computeIconAriaHidden_(narrow) { return Boolean(!narrow || this.hasSearchText).toString(); - }, + } /** * @return {boolean} @@ -123,12 +140,12 @@ this.$.spinnerTemplate.if = true; } return showSpinner; - }, + } /** @private */ onInputFocus_() { this.searchFocused_ = true; - }, + } /** @private */ onInputBlur_() { @@ -136,14 +153,14 @@ if (!this.hasSearchText) { this.showingSearch = false; } - }, + } /** @private */ onSearchTermKeydown_(e) { if (e.key === 'Escape') { this.showingSearch = false; } - }, + } /** * @param {Event} e @@ -153,7 +170,7 @@ if (e.target !== this.$.clearSearch) { this.showingSearch = true; } - }, + } /** * @param {Event} e @@ -163,7 +180,7 @@ this.setValue(''); this.focus_(); this.spinnerActive = false; - }, + } /** * @param {boolean} current @@ -183,5 +200,8 @@ this.setValue(''); this.getSearchInput().blur(); - }, -}); + } +} + +customElements.define( + CrToolbarSearchFieldElement.is, CrToolbarSearchFieldElement);
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc index 26f4e70..0c8d1de1b 100644 --- a/weblayer/app/content_main_delegate_impl.cc +++ b/weblayer/app/content_main_delegate_impl.cc
@@ -178,6 +178,8 @@ blink::features::kPortals, // TODO(crbug.com/1174566): Enable by default after experiment. content_capture::features::kContentCapture, + // TODO(crbug.com/1144912): Support BackForwardCache on WebLayer. + ::features::kBackForwardCache, #if defined(OS_ANDROID) // TODO(crbug.com/1131016): Support Picture in Picture API on WebLayer.
diff --git a/weblayer/browser/browser_context_impl.cc b/weblayer/browser/browser_context_impl.cc index aad4f42..431ae2b 100644 --- a/weblayer/browser/browser_context_impl.cc +++ b/weblayer/browser/browser_context_impl.cc
@@ -276,6 +276,8 @@ embedder_support::kAlternateErrorPagesEnabled, true); pref_registry->RegisterListPref( site_isolation::prefs::kUserTriggeredIsolatedOrigins); + pref_registry->RegisterDictionaryPref( + site_isolation::prefs::kWebTriggeredIsolatedOrigins); StatefulSSLHostStateDelegate::RegisterProfilePrefs(pref_registry); HostContentSettingsMap::RegisterProfilePrefs(pref_registry);
diff --git a/weblayer/browser/persistence/browser_persister.cc b/weblayer/browser/persistence/browser_persister.cc index 3b15de2..2298243 100644 --- a/weblayer/browser/persistence/browser_persister.cc +++ b/weblayer/browser/persistence/browser_persister.cc
@@ -61,7 +61,7 @@ sessions::CommandStorageManager::kOther, path, this, - /* use_marker */ false, + /* use_marker */ true, browser->profile()->GetBrowserContext()->IsOffTheRecord(), decryption_key)), rebuild_on_next_save_(false), @@ -106,8 +106,8 @@ } void BrowserPersister::OnErrorWritingSessionCommands() { - // TODO(https://crbug.com/648266): implement this. - NOTIMPLEMENTED(); + rebuild_on_next_save_ = true; + command_storage_manager_->StartSaveTimer(); } void BrowserPersister::OnTabAdded(Tab* tab) {
diff --git a/weblayer/browser/persistence/browser_persister_browsertest.cc b/weblayer/browser/persistence/browser_persister_browsertest.cc index f1c5680..5ab10e2 100644 --- a/weblayer/browser/persistence/browser_persister_browsertest.cc +++ b/weblayer/browser/persistence/browser_persister_browsertest.cc
@@ -418,4 +418,35 @@ } } +IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, OnErrorWritingSessionCommands) { + ASSERT_TRUE(embedded_test_server()->Start()); + + std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x"); + Tab* tab = browser->CreateTab(); + EXPECT_TRUE(browser->IsRestoringPreviousState()); + const GURL url = embedded_test_server()->GetURL("/simple_page.html"); + NavigateAndWaitForCompletion(url, tab); + static_cast<sessions::CommandStorageManagerDelegate*>( + browser->browser_persister()) + ->OnErrorWritingSessionCommands(); + ShutdownBrowserPersisterAndWait(browser.get()); + tab = nullptr; + browser.reset(); + + browser = CreateBrowser(GetProfile(), "x"); + // Should be no tabs while waiting for restore. + EXPECT_TRUE(browser->GetTabs().empty()); + EXPECT_TRUE(browser->IsRestoringPreviousState()); + // Wait for the restore and navigation to complete. + BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation( + browser.get(), url); + + ASSERT_EQ(1u, browser->GetTabs().size()); + EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab()); + EXPECT_EQ(1, browser->GetTabs()[0] + ->GetNavigationController() + ->GetNavigationListSize()); + EXPECT_FALSE(browser->IsRestoringPreviousState()); +} + } // namespace weblayer