diff --git a/BUILD.gn b/BUILD.gn index 19aee8c..1985d70f 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -257,6 +257,12 @@ "//media/cast:cast_unittests", "//third_party/catapult/telemetry:bitmaptools($host_toolchain)", ] + if (is_android) { + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + deps += [ "//chrome/test:telemetry_perf_unittests${_target_suffix}" ] + } + } } else if (is_ios) { deps += [ "//ios:all", @@ -823,6 +829,12 @@ ] if (is_android) { deps += [ "//chrome/browser/android/vr:vr_android_unittests" ] + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + deps += [ + "//tools/perf/contrib/vr_benchmarks:vr_perf_tests${_target_suffix}", + ] + } } }
diff --git a/DEPS b/DEPS index d6616ff..c601d53 100644 --- a/DEPS +++ b/DEPS
@@ -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': '357e67e7af3b95411f3f8426ca5de4767eb85d07', + 'skia_revision': 'a1a3afe95136aa688372af3047ef9d3a4688096b', # 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,11 +221,11 @@ # 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': 'fec39fa1fc5985d07d6ae5fb39121b695d553488', + 'angle_revision': '10f15011da42241e7053bd8a9d95d3a876faf75d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'c1e4abc1bcfeae3ea17279b1f3d419406769c77d', + 'swiftshader_revision': 'efe254de5d881c3d65030c6a5801d6969f9dde35', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -328,11 +328,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'b3c371031cc85b7af53d50386c7865fcb35a0a6a', + 'dawn_revision': 'cac1d35f71cc361952a6da85588844da20600bf8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '9c1a2f0b79044aa9061f0eb2b12b4ace2b275045', + 'quiche_revision': '3e33fe15f6f82bc1287dbf0f4aa2bfe2be1c9e5b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -730,7 +730,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '5wEAJbMDQJnCxXbN6hMn66IR4akg1G25HQtc_8_7Vz0C', + 'version': '8d-gGcc4KVhOnn2B-Od7eR421Q-sNZQ0U7dMrNz_VX4C', }, ], 'condition': 'checkout_android', @@ -966,7 +966,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '85557a08f4918c65b5bc18868eaeb18e19800983', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9705687c250c2f5a3e5eb5e9491ded272f53cdc1', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1106,7 +1106,7 @@ Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '18e09b9197a3b1d771c077c530d1a4ebad04c167', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f022e298b4f4a782486bb6d5ce6589c998b51fe2', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'a0718d4f121727e30b8d52c7a189ebf5ab52421f', 'src/third_party/icu4j': { 'packages': [ @@ -1349,7 +1349,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd355130be3c1738804c6cf787a1ff31886f539db', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ae2171b89cb3e49f73ff100fc1647a93048ca472', '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@d39bb223cf04dea5d35cbd982e140d1540f96352', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@7fd6569e6ad333383889e84dffb17db00bc1ed00', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a', @@ -1571,10 +1571,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a0b8774ce8cec1dc8f4308810bf05eb8867c62de', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7c0e4f92088f8230bd63a81b9b924fb9dadc5be8', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'd3af0bf85d4771b0809a4571bb01ac3f8edeb8a0', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '2a25a969731da40dbcf3468ff58713ea5c643484', + Var('webrtc_git') + '/src.git' + '@' + '43eb4f588646c346c97a1e1c1dda00dd837b13db', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1601,7 +1601,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'v0j61b0DK560O1WaRwZ_kGgqR39JhxCdufdFIIheSfAC', + 'version': 'fVbmAq5SyEKlNV_cPvOrlJbBRmDAWApv309sIMdbgq8C', }, ], 'dep_type': 'cipd', @@ -1611,7 +1611,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'JItKnXhnS8XOC3pfEti_mAl6ez2Dgk_qSjs5wXeG5xEC', + 'version': 'hySBvc3hf9NRFmfS2oG52F9ZzLpvX9bFuyybtZ92CNAC', }, ], 'dep_type': 'cipd', @@ -1621,7 +1621,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'WB42GE3e_7-dR5RnBBCICQtMkfpOoJvlT9tMG_6Fj1UC', + 'version': 'SGAjTHEDDOpAgPQYJcSEmMh4E6afvlKQKzBjwSTf5dwC', }, ], '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@0643b2b983dd1126e4702664fde75dce35f06f2f', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3ed0d614fb4afb27e048f1ff9e387a4885794a04', 'condition': 'checkout_src_internal', }, @@ -1665,7 +1665,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'Y11GYI292bpvaXxkHj9X5tufQUeYgOWKF_Ozds2OB7MC', + 'version': 'nZQbCLVLZXhqeQVND_suj9_gQyVSt-tl7jFkdicBEyYC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 3a07e2d..61ec9599 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -1142,8 +1142,8 @@ 'build/android/gyp/prepare_resources.pydeps', 'build/android/gyp/process_native_prebuilt.pydeps', 'build/android/gyp/proguard.pydeps', - 'build/android/gyp/resources_shrinker/shrinker.pydeps', 'build/android/gyp/turbine.pydeps', + 'build/android/gyp/unused_resources.pydeps', 'build/android/gyp/validate_static_library_dex_references.pydeps', 'build/android/gyp/write_build_config.pydeps', 'build/android/gyp/write_native_libraries_java.pydeps',
diff --git a/WATCHLISTS b/WATCHLISTS index 7af6ca7..0b42058 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1444,11 +1444,14 @@ }, 'omnibox': { 'filepath': '^chrome/browser/autocomplete/|'\ + '^chrome/browser/resources/new_tab_page/realbox/|'\ '^chrome/browser/resources/omnibox|'\ '^chrome/browser/ui/location_bar/|'\ '^chrome/browser/ui/omnibox/|'\ '^chrome/browser/ui/.*/location_bar/|'\ '^chrome/browser/ui/.*/omnibox/|'\ + '^chrome/browser/ui/.*/realbox/|'\ + '^chrome/test/data/webui/new_tab_page/realbox/|'\ '^components/omnibox/|'\ '^components/search_engines/' },
diff --git a/android_webview/browser/gfx/overlay_processor_webview.cc b/android_webview/browser/gfx/overlay_processor_webview.cc index cbd13266..039192c 100644 --- a/android_webview/browser/gfx/overlay_processor_webview.cc +++ b/android_webview/browser/gfx/overlay_processor_webview.cc
@@ -176,7 +176,7 @@ return; gpu_thread_sequence_ = std::make_unique<gpu::SchedulerSequence>( - gpu_service->GetGpuScheduler()); + gpu_service->GetGpuScheduler(), gpu_service->main_runner()); render_thread_sequence_->ScheduleGpuTask( base::BindOnce(&OverlayProcessorWebView::Manager::SetGpuService,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index da3f602..547d6e7 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1834,6 +1834,7 @@ "//base", "//base:i18n", "//base/third_party/dynamic_annotations", + "//base/util/timer", "//base/util/values:values_util", "//build:branding_buildflags", "//cc", @@ -1888,6 +1889,7 @@ "//components/services/app_service/public/cpp:app_update", "//components/session_manager:base", "//components/session_manager/core", + "//components/soda", "//components/strings", "//components/sync", "//components/user_manager", @@ -2473,6 +2475,7 @@ "//ash/system/machine_learning:user_settings_event_proto", "//base", "//base/test:test_support", + "//base/util/timer:timer", "//base/util/values:values_util", "//build:branding_buildflags", "//chromeos:test_support", @@ -2510,6 +2513,7 @@ "//components/quirks", "//components/services/app_service/public/cpp:app_update", "//components/session_manager/core", + "//components/soda", "//components/sync_preferences:test_support", "//components/ukm:test_support", "//components/user_manager",
diff --git a/ash/DEPS b/ash/DEPS index 21fb9e2..5ff9d8e 100644 --- a/ash/DEPS +++ b/ash/DEPS
@@ -15,6 +15,7 @@ "+components/quirks", "+components/services/app_service/public", "+components/session_manager", + "+components/soda", "+components/strings", "+components/sync", "+components/ui_devtools",
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc index 766e31a..2e73015 100644 --- a/ash/accelerators/accelerator_controller_impl.cc +++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -259,10 +259,13 @@ prefs::kImprovedShortcutsNotificationShownCount); } -bool IsGuestUserSession() { +bool ShouldShowStartupNotificationForCurrentUser() { const absl::optional<user_manager::UserType> user_type = Shell::Get()->session_controller()->GetUserType(); - return user_type && *user_type == user_manager::USER_TYPE_GUEST; + return user_type && + (*user_type == user_manager::USER_TYPE_REGULAR || + *user_type == user_manager::USER_TYPE_CHILD) && + !Shell::Get()->session_controller()->IsUserFirstLogin(); } // Increments the number of times the startup notification has been shown @@ -1815,8 +1818,10 @@ PrefService* pref_service) { DCHECK(pref_service); if (::features::IsImprovedKeyboardShortcutsEnabled()) { - if (should_show_shortcut_notification_ && !IsGuestUserSession()) + if (should_show_shortcut_notification_ && + ShouldShowStartupNotificationForCurrentUser()) { NotifyShortcutChangesInRelease(pref_service); + } } }
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index e2ec226..8182e01 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -2316,6 +2316,19 @@ } TEST_F(AcceleratorControllerStartupNotificationTest, + StartupNotificationNotShownWhenInFirstLogin) { + // Set up the shell and controller. + SetUpLater(/*improved_shortcuts_enabled=*/true); + + SimulateNewUserFirstLogin("user1@email.com"); + + // Notification should not be shown at a new user's first login. + auto* notification = message_center()->FindVisibleNotificationById( + kStartupNewShortcutNotificationId); + EXPECT_FALSE(notification); +} + +TEST_F(AcceleratorControllerStartupNotificationTest, StartupNotificationShownOnlyOnce) { // Set up the shell and controller. SetUpLater(/*improved_shortcuts_enabled=*/true);
diff --git a/ash/ambient/test/ambient_ash_test_base.h b/ash/ambient/test/ambient_ash_test_base.h index b03de74..6e92cb0 100644 --- a/ash/ambient/test/ambient_ash_test_base.h +++ b/ash/ambient/test/ambient_ash_test_base.h
@@ -13,6 +13,7 @@ #include "ash/ambient/ambient_controller.h" #include "ash/ambient/test/test_ambient_client.h" #include "ash/ambient/ui/ambient_background_image_view.h" +#include "ash/public/cpp/test/test_image_downloader.h" #include "ash/test/ash_test_base.h" #include "services/media_session/public/mojom/media_session.mojom.h" #include "ui/views/view.h" @@ -177,6 +178,7 @@ private: std::unique_ptr<views::Widget> widget_; power_manager::PowerSupplyProperties proto_; + TestImageDownloader image_downloader_; }; } // namespace ash
diff --git a/ash/ambient/test/ambient_ash_test_helper.cc b/ash/ambient/test/ambient_ash_test_helper.cc index c8ee548..a4503b7 100644 --- a/ash/ambient/test/ambient_ash_test_helper.cc +++ b/ash/ambient/test/ambient_ash_test_helper.cc
@@ -5,12 +5,10 @@ #include "ash/ambient/test/ambient_ash_test_helper.h" #include "ash/ambient/test/test_ambient_client.h" -#include "ash/public/cpp/test/test_image_downloader.h" namespace ash { AmbientAshTestHelper::AmbientAshTestHelper() { - image_downloader_ = std::make_unique<TestImageDownloader>(); ambient_client_ = std::make_unique<TestAmbientClient>(&wake_lock_provider_); }
diff --git a/ash/ambient/test/ambient_ash_test_helper.h b/ash/ambient/test/ambient_ash_test_helper.h index 7ec665b..651fcda 100644 --- a/ash/ambient/test/ambient_ash_test_helper.h +++ b/ash/ambient/test/ambient_ash_test_helper.h
@@ -11,7 +11,6 @@ namespace ash { -class TestImageDownloader; class TestAmbientClient; // The helper class to test the Ambient Mode in Ash. @@ -31,7 +30,6 @@ } private: - std::unique_ptr<TestImageDownloader> image_downloader_; device::TestWakeLockProvider wake_lock_provider_; std::unique_ptr<TestAmbientClient> ambient_client_; };
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc index 5f05855..2be0104 100644 --- a/ash/app_list/app_list_presenter_unittest.cc +++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -88,6 +88,7 @@ #include "ui/events/event_constants.h" #include "ui/events/test/event_generator.h" #include "ui/touch_selection/touch_selection_menu_runner.h" +#include "ui/views/animation/bounds_animator.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield_test_api.h"
diff --git a/ash/app_list/bubble/app_list_bubble_apps_page.cc b/ash/app_list/bubble/app_list_bubble_apps_page.cc index 8fb47a1..7a6e3a8 100644 --- a/ash/app_list/bubble/app_list_bubble_apps_page.cc +++ b/ash/app_list/bubble/app_list_bubble_apps_page.cc
@@ -9,7 +9,9 @@ #include <string> #include <utility> +#include "ash/app_list/app_list_view_delegate.h" #include "ash/app_list/bubble/scrollable_apps_grid_view.h" +#include "ash/app_list/model/app_list_model.h" #include "ash/bubble/bubble_utils.h" #include "base/check.h" #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/ash/app_list/bubble/scrollable_apps_grid_view.cc b/ash/app_list/bubble/scrollable_apps_grid_view.cc index 9b9ec41..d43e2e8d 100644 --- a/ash/app_list/bubble/scrollable_apps_grid_view.cc +++ b/ash/app_list/bubble/scrollable_apps_grid_view.cc
@@ -7,8 +7,10 @@ #include <limits> #include <memory> +#include "ash/app_list/model/app_list_model.h" #include "ash/app_list/views/app_list_item_view.h" #include "ash/public/cpp/app_list/app_list_config.h" +#include "ui/views/animation/bounds_animator.h" #include "ui/views/view_model_utils.h" namespace ash { @@ -92,7 +94,7 @@ } void ScrollableAppsGridView::CalculateIdealBounds() { - DCHECK(!is_in_folder()); + DCHECK(!IsInFolder()); int grid_index = 0; int model_index = 0;
diff --git a/ash/app_list/paged_view_structure.cc b/ash/app_list/paged_view_structure.cc index f8073f22..b3c8002 100644 --- a/ash/app_list/paged_view_structure.cc +++ b/ash/app_list/paged_view_structure.cc
@@ -7,6 +7,8 @@ #include <algorithm> #include "ash/app_list/model/app_list_item.h" +#include "ash/app_list/model/app_list_item_list.h" +#include "ash/app_list/model/app_list_model.h" #include "ash/app_list/views/app_list_item_view.h" #include "ash/app_list/views/apps_grid_view.h" #include "base/containers/contains.h"
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index a607356..21b40b2 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -13,7 +13,6 @@ #include "ash/app_list/model/app_list_folder_item.h" #include "ash/app_list/model/app_list_item.h" #include "ash/app_list/views/app_list_menu_model_adapter.h" -#include "ash/app_list/views/apps_grid_view.h" #include "ash/public/cpp/app_list/app_list_color_provider.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_switches.h" @@ -256,17 +255,17 @@ DISALLOW_COPY_AND_ASSIGN(IconImageView); }; -AppListItemView::AppListItemView(AppsGridView* apps_grid_view, +AppListItemView::AppListItemView(GridDelegate* grid_delegate, AppListItem* item, - AppListViewDelegate* delegate) - : Button(), - is_folder_(item->GetItemType() == AppListFolderItem::kItemType), + AppListViewDelegate* view_delegate) + : is_folder_(item->GetItemType() == AppListFolderItem::kItemType), item_weak_(item), - delegate_(delegate), - apps_grid_view_(apps_grid_view), + grid_delegate_(grid_delegate), + view_delegate_(view_delegate), is_notification_indicator_enabled_( features::IsNotificationIndicatorEnabled()) { - DCHECK(delegate_); + DCHECK(grid_delegate_); + DCHECK(view_delegate_); SetFocusBehavior(FocusBehavior::ALWAYS); auto title = std::make_unique<views::Label>(); @@ -275,7 +274,7 @@ title->SetFontList(GetAppListConfig().app_title_font()); title->SetHorizontalAlignment(gfx::ALIGN_CENTER); title->SetEnabledColor(AppListColorProvider::Get()->GetAppListItemTextColor( - apps_grid_view_->is_in_folder())); + grid_delegate_->IsInFolder())); icon_ = AddChildView(std::make_unique<IconImageView>()); @@ -283,7 +282,7 @@ // Set background blur for folder icon and use mask layer to clip it into // circle. Note that blur is only enabled in tablet mode to improve dragging // smoothness. - if (delegate_->IsInTabletMode()) + if (view_delegate_->IsInTabletMode()) SetBackgroundBlurEnabled(true); icon_->SetExtendedState(GetAppListConfig(), false /*extended*/, false /*animate*/); @@ -393,7 +392,7 @@ SetIcon(icon_image_); layer()->SetTransform(gfx::GetScaleTransform( GetContentsBounds().CenterPoint(), 1 / kDragDropAppIconScale)); - } else if (apps_grid_view_->IsDraggedView(this)) { + } else if (grid_delegate_->IsDraggedView(this)) { // If a drag view has been created for this icon, the item transition to // target bounds is handled by the apps grid view bounds animator. At the // end of that animation, the layer will be destroyed, causing the @@ -419,7 +418,7 @@ } else { if (is_folder_) { layer()->SetTransform(gfx::Transform()); - } else if (!apps_grid_view_->IsDraggedView(this)) { + } else if (!grid_delegate_->IsDraggedView(this)) { // To avoid poor quality icons, update icon image with the correct scale // after the transform animation is completed. settings.AddObserver(this); @@ -444,7 +443,7 @@ // EndDrag may delete |this|. if (!touch_dragging) - apps_grid_view_->EndDrag(/*cancel=*/false); + grid_delegate_->EndDrag(/*cancel=*/false); } void AppListItemView::SetMouseDragging(bool mouse_dragging) { @@ -463,8 +462,7 @@ const gfx::Point& tap_down_location, const gfx::Point& tap_down_root_location) { // Show scaled up app icon to indicate draggable state. - apps_grid_view_->InitiateDrag(this, AppsGridView::TOUCH, tap_down_location, - tap_down_root_location); + grid_delegate_->InitiateDrag(this, tap_down_location, tap_down_root_location); SetTouchDragging(true); } @@ -501,7 +499,7 @@ } const AppListConfig& AppListItemView::GetAppListConfig() const { - return apps_grid_view_->GetAppListConfig(); + return grid_delegate_->GetAppListConfig(); } void AppListItemView::SetItemName(const std::u16string& display_name, @@ -558,16 +556,16 @@ return; // GetContextMenuModel is asynchronous and takes a nontrivial amount of time - // to complete. If a menu is shown after the icon has moved, |apps_grid_view_| + // to complete. If a menu is shown after the icon has moved, |grid_delegate_| // gets put in a bad state because the context menu begins to receive drag // events, interrupting the app icon drag. - if (apps_grid_view_->IsDragViewMoved(*this)) + if (grid_delegate_->IsDragViewMoved(*this)) return; menu_show_initiated_from_key_ = source_type == ui::MENU_SOURCE_KEYBOARD; - if (!apps_grid_view_->IsSelectedView(this)) - apps_grid_view_->ClearAnySelectedView(); + if (!grid_delegate_->IsSelectedView(this)) + grid_delegate_->ClearAnySelectedView(); int run_types = views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::USE_TOUCHABLE_LAYOUT | @@ -578,24 +576,24 @@ run_types |= views::MenuRunner::SEND_GESTURE_EVENTS_TO_OWNER; gfx::Rect anchor_rect = - parent()->GetMirroredRect(apps_grid_view_->GetIdealBounds(this)); + parent()->GetMirroredRect(grid_delegate_->GetIdealBounds(this)); // Anchor the menu to the same rect that is used for selection highlight. AdaptBoundsForSelectionHighlight(&anchor_rect); views::View::ConvertRectToScreen(parent(), &anchor_rect); AppLaunchedMetricParams metric_params = { AppListLaunchedFrom::kLaunchedFromGrid}; - delegate_->GetAppLaunchedMetricParams(&metric_params); + view_delegate_->GetAppLaunchedMetricParams(&metric_params); context_menu_ = std::make_unique<AppListMenuModelAdapter>( item_weak_->GetMetadata()->id, std::move(menu_model), GetWidget(), source_type, metric_params, AppListMenuModelAdapter::FULLSCREEN_APP_GRID, base::BindOnce(&AppListItemView::OnMenuClosed, weak_ptr_factory_.GetWeakPtr()), - delegate_->IsInTabletMode()); + view_delegate_->IsInTabletMode()); context_menu_->Run(anchor_rect, views::MenuAnchorPosition::kBubbleRight, run_types); - apps_grid_view_->SetSelectedView(this); + grid_delegate_->SetSelectedView(this); } void AppListItemView::ShowContextMenuForViewImpl( @@ -611,7 +609,7 @@ if (waiting_for_context_menu_options_) return; waiting_for_context_menu_options_ = true; - delegate_->GetContextMenuModel( + view_delegate_->GetContextMenuModel( item_weak_->id(), base::BindOnce(&AppListItemView::OnContextMenuModelReceived, weak_ptr_factory_.GetWeakPtr(), point, source_type)); @@ -627,27 +625,27 @@ } void AppListItemView::PaintButtonContents(gfx::Canvas* canvas) { - if (apps_grid_view_->IsDraggedView(this)) + if (grid_delegate_->IsDraggedView(this)) return; // TODO(ginko) focus and selection should be unified. - if ((apps_grid_view_->IsSelectedView(this) || HasFocus()) && - (delegate_->KeyboardTraversalEngaged() || + if ((grid_delegate_->IsSelectedView(this) || HasFocus()) && + (view_delegate_->KeyboardTraversalEngaged() || waiting_for_context_menu_options_ || (context_menu_ && context_menu_->IsShowingMenu()))) { cc::PaintFlags flags; flags.setAntiAlias(true); - if (delegate_->KeyboardTraversalEngaged()) { + if (view_delegate_->KeyboardTraversalEngaged()) { flags.setColor(AppListColorProvider::Get()->GetFocusRingColor()); flags.setStyle(cc::PaintFlags::kStroke_Style); flags.setStrokeWidth(kFocusRingWidth); } else { const AppListColorProvider* color_provider = AppListColorProvider::Get(); - const SkColor bg_color = apps_grid_view_->is_in_folder() - ? color_provider->GetFolderBackgroundColor( - apps_grid_view_->GetAppListConfig() - .folder_background_color()) - : gfx::kPlaceholderColor; + const SkColor bg_color = + grid_delegate_->IsInFolder() + ? color_provider->GetFolderBackgroundColor( + GetAppListConfig().folder_background_color()) + : gfx::kPlaceholderColor; flags.setColor(SkColorSetA( color_provider->GetRippleAttributesBaseColor(bg_color), color_provider->GetRippleAttributesHighlightOpacity(bg_color) * 255)); @@ -679,10 +677,9 @@ if (!ShouldEnterPushedState(event)) return true; - apps_grid_view_->InitiateDrag(this, AppsGridView::MOUSE, event.location(), - event.root_location()); + grid_delegate_->InitiateDrag(this, event.location(), event.root_location()); - if (apps_grid_view_->IsDraggedView(this)) { + if (grid_delegate_->IsDraggedView(this)) { mouse_drag_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kMouseDragUIDelayInMs), this, &AppListItemView::OnMouseDragTimer); @@ -701,7 +698,7 @@ gfx::Rect title_bounds = GetTitleBoundsForTargetViewBounds( GetAppListConfig(), rect, title_->GetPreferredSize(), icon_scale_); - if (!apps_grid_view_->is_in_folder()) + if (!grid_delegate_->IsInFolder()) title_bounds.Inset(title_shadow_margins_); title_->SetBoundsRect(title_bounds); @@ -730,7 +727,7 @@ SetMouseDragging(false); // EndDrag may delete |this|. - apps_grid_view_->EndDrag(false /*cancel*/); + grid_delegate_->EndDrag(false /*cancel*/); } void AppListItemView::OnMouseCaptureLost() { @@ -738,27 +735,27 @@ SetMouseDragging(false); // EndDrag may delete |this|. - apps_grid_view_->EndDrag(true /*cancel*/); + grid_delegate_->EndDrag(true /*cancel*/); } bool AppListItemView::OnMouseDragged(const ui::MouseEvent& event) { Button::OnMouseDragged(event); - if (apps_grid_view_->IsDraggedView(this) && mouse_dragging_) { + if (grid_delegate_->IsDraggedView(this) && mouse_dragging_) { // Update the drag location of the drag proxy if it has been created. // If the drag is no longer happening, it could be because this item // got removed, in which case this item has been destroyed. So, bail out // now as there will be nothing else to do anyway as - // apps_grid_view_->dragging() will be false. - if (!apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, event)) + // grid_delegate_->dragging() will be false. + if (!grid_delegate_->UpdateDragFromItem(/*is_touch=*/false, event)) return true; } - if (!apps_grid_view_->IsSelectedView(this)) - apps_grid_view_->ClearAnySelectedView(); + if (!grid_delegate_->IsSelectedView(this)) + grid_delegate_->ClearAnySelectedView(); // Show dragging UI when it's confirmed without waiting for the timer. - if (ui_state_ != UI_STATE_DRAGGING && apps_grid_view_->dragging() && - apps_grid_view_->IsDraggedView(this)) { + if (ui_state_ != UI_STATE_DRAGGING && grid_delegate_->IsDragging() && + grid_delegate_->IsDraggedView(this)) { mouse_drag_timer_.Stop(); SetUIState(UI_STATE_DRAGGING); } @@ -774,12 +771,12 @@ void AppListItemView::OnFocus() { if (focus_silently_) return; - apps_grid_view_->SetSelectedView(this); + grid_delegate_->SetSelectedView(this); } void AppListItemView::OnBlur() { SchedulePaint(); - apps_grid_view_->ClearSelectedView(this); + grid_delegate_->ClearSelectedView(this); } void AppListItemView::OnGestureEvent(ui::GestureEvent* event) { @@ -787,16 +784,15 @@ case ui::ET_GESTURE_SCROLL_BEGIN: if (touch_dragging_) { CancelContextMenu(); - apps_grid_view_->StartDragAndDropHostDragAfterLongPress( - AppsGridView::TOUCH); + grid_delegate_->StartDragAndDropHostDragAfterLongPress(); event->SetHandled(); } else { touch_drag_timer_.Stop(); } break; case ui::ET_GESTURE_SCROLL_UPDATE: - if (touch_dragging_ && apps_grid_view_->IsDraggedView(this)) { - apps_grid_view_->UpdateDragFromItem(AppsGridView::TOUCH, *event); + if (touch_dragging_ && grid_delegate_->IsDraggedView(this)) { + grid_delegate_->UpdateDragFromItem(/*is_touch=*/true, *event); event->SetHandled(); } break; @@ -831,7 +827,7 @@ touch_drag_timer_.Stop(); SetTouchDragging(false); if (context_menu_ && context_menu_->IsShowingMenu()) - apps_grid_view_->SetSelectedView(this); + grid_delegate_->SetSelectedView(this); break; case ui::ET_GESTURE_TWO_FINGER_TAP: if (touch_dragging_) { @@ -850,7 +846,7 @@ void AppListItemView::OnThemeChanged() { views::Button::OnThemeChanged(); title_->SetEnabledColor(AppListColorProvider::Get()->GetAppListItemTextColor( - apps_grid_view_->is_in_folder())); + grid_delegate_->IsInFolder())); SchedulePaint(); }
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h index 2e25287b..fefdd6b 100644 --- a/ash/app_list/views/app_list_item_view.h +++ b/ash/app_list/views/app_list_item_view.h
@@ -8,7 +8,6 @@ #include <memory> #include <string> #include <utility> -#include <vector> #include "ash/app_list/model/app_list_item_observer.h" #include "ash/ash_export.h" @@ -18,7 +17,13 @@ #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/button.h" +namespace gfx { +class Point; +class Rect; +} // namespace gfx + namespace ui { +class LocatedEvent; class SimpleMenuModel; } // namespace ui @@ -32,8 +37,10 @@ class AppListItem; class AppListMenuModelAdapter; class AppListViewDelegate; -class AppsGridView; +// An application icon and title. Commonly part of the AppsGridView, but may be +// used in other contexts. Supports dragging and keyboard selection via the +// GridDelegate interface. class ASH_EXPORT AppListItemView : public views::Button, public views::ContextMenuController, public AppListItemObserver, @@ -41,9 +48,47 @@ public: METADATA_HEADER(AppListItemView); - AppListItemView(AppsGridView* apps_grid_view, + // The parent apps grid (AppsGridView) or a stub. Not named "Delegate" to + // differentiate it from AppListViewDelegate. + class GridDelegate { + public: + virtual ~GridDelegate() = default; + + // Whether the parent apps grid (if any) is a folder. + virtual bool IsInFolder() const = 0; + + // Methods for keyboard selection. + virtual void SetSelectedView(AppListItemView* view) = 0; + virtual void ClearSelectedView(AppListItemView* view) = 0; + virtual void ClearAnySelectedView() = 0; + virtual bool IsSelectedView(const AppListItemView* view) const = 0; + + virtual void InitiateDrag(AppListItemView* view, + const gfx::Point& location, + const gfx::Point& root_location) = 0; + virtual void StartDragAndDropHostDragAfterLongPress() = 0; + + // Called from AppListItemView when it receives a drag event. Returns true + // if the drag is still happening. + virtual bool UpdateDragFromItem(bool is_touch, + const ui::LocatedEvent& event) = 0; + virtual void EndDrag(bool cancel) = 0; + virtual bool IsDragging() const = 0; + virtual bool IsDraggedView(const AppListItemView* view) const = 0; + + // Whether |view| is being dragged and is not in its drag start position. + virtual bool IsDragViewMoved(const AppListItemView& view) const = 0; + + // Returns the ideal bounds for `view` in AppsGridView coordinates. + virtual const gfx::Rect& GetIdealBounds(AppListItemView* view) const = 0; + + // TODO(crbug.com/1211592): Eliminate this method. + virtual const AppListConfig& GetAppListConfig() const = 0; + }; + + AppListItemView(GridDelegate* grid_delegate, AppListItem* item, - AppListViewDelegate* delegate); + AppListViewDelegate* view_delegate); AppListItemView(const AppListItemView&) = delete; AppListItemView& operator=(const AppListItemView&) = delete; ~AppListItemView() override; @@ -253,8 +298,13 @@ AppListItem* item_weak_; // Owned by AppListModel. Can be nullptr. - AppListViewDelegate* delegate_; // Unowned. - AppsGridView* apps_grid_view_; // Parent view, owns this. + // Handles dragging and item selection. Might be a stub for items that are not + // part of an apps grid. + GridDelegate* const grid_delegate_; + + // AppListControllerImpl by another name. + AppListViewDelegate* const view_delegate_; + IconImageView* icon_ = nullptr; // Strongly typed child view. views::Label* title_ = nullptr; // Strongly typed child view.
diff --git a/ash/app_list/views/app_list_main_view.cc b/ash/app_list/views/app_list_main_view.cc index 47f4873d..ba293ed 100644 --- a/ash/app_list/views/app_list_main_view.cc +++ b/ash/app_list/views/app_list_main_view.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <memory> +#include <string> #include <utility> #include "ash/app_list/app_list_metrics.h" @@ -15,6 +16,7 @@ #include "ash/app_list/model/app_list_model.h" #include "ash/app_list/views/app_list_folder_view.h" #include "ash/app_list/views/app_list_item_view.h" +#include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/apps_container_view.h" #include "ash/app_list/views/apps_grid_view.h" #include "ash/app_list/views/contents_view.h"
diff --git a/ash/app_list/views/app_list_main_view_unittest.cc b/ash/app_list/views/app_list_main_view_unittest.cc index 7564134b..4a680f83 100644 --- a/ash/app_list/views/app_list_main_view_unittest.cc +++ b/ash/app_list/views/app_list_main_view_unittest.cc
@@ -5,11 +5,13 @@ #include "ash/app_list/views/app_list_main_view.h" #include <memory> +#include <string> #include "ash/app_list/app_list_test_view_delegate.h" #include "ash/app_list/model/app_list_test_model.h" #include "ash/app_list/views/app_list_folder_view.h" #include "ash/app_list/views/app_list_item_view.h" +#include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/apps_container_view.h" #include "ash/app_list/views/apps_grid_view.h" #include "ash/app_list/views/apps_grid_view_test_api.h" @@ -96,7 +98,6 @@ // |point| is in |grid_view|'s coordinates. AppListItemView* SimulateInitiateDrag(AppsGridView* grid_view, - AppsGridView::Pointer pointer, const gfx::Point& point) { AppListItemView* view = GetItemViewAtPointInGrid(grid_view, point); DCHECK(view); @@ -106,7 +107,7 @@ gfx::Point root_window_point = point; views::View::ConvertPointToWidget(grid_view, &root_window_point); - grid_view->InitiateDrag(view, pointer, root_window_point, point); + grid_view->InitiateDrag(view, root_window_point, point); return view; } @@ -184,9 +185,8 @@ AppListItemView* StartDragForReparent(int index_in_folder) { // Start to drag the item in folder. views::View* item_view = GetFolderViewModel()->view_at(index_in_folder); - AppListItemView* dragged = - SimulateInitiateDrag(GetFolderGridView(), AppsGridView::MOUSE, - item_view->bounds().CenterPoint()); + AppListItemView* dragged = SimulateInitiateDrag( + GetFolderGridView(), item_view->bounds().CenterPoint()); EXPECT_EQ(item_view, dragged); EXPECT_TRUE(GetRootGridView()->GetVisible()); EXPECT_TRUE(GetFolderView()->GetVisible());
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 16824a57..40b4135 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -20,6 +20,7 @@ #include "ash/app_list/views/app_list_folder_view.h" #include "ash/app_list/views/app_list_item_view.h" #include "ash/app_list/views/app_list_main_view.h" +#include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/apps_container_view.h" #include "ash/app_list/views/contents_view.h" #include "ash/app_list/views/ghost_image_view.h" @@ -55,6 +56,7 @@ #include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/bounds_animator.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" @@ -420,6 +422,10 @@ Update(); } +bool AppsGridView::IsInFolder() const { + return !!folder_delegate_; +} + void AppsGridView::SetSelectedView(AppListItemView* view) { if (IsSelectedView(view) || IsDraggedView(view)) return; @@ -453,7 +459,6 @@ } void AppsGridView::InitiateDrag(AppListItemView* view, - Pointer pointer, const gfx::Point& location, const gfx::Point& root_location) { DCHECK(view); @@ -476,8 +481,8 @@ drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y()); } -void AppsGridView::StartDragAndDropHostDragAfterLongPress(Pointer pointer) { - TryStartDragAndDropHostDrag(pointer, drag_start_grid_view_); +void AppsGridView::StartDragAndDropHostDragAfterLongPress() { + TryStartDragAndDropHostDrag(TOUCH, drag_start_grid_view_); } void AppsGridView::TryStartDragAndDropHostDrag( @@ -497,7 +502,7 @@ StartDragAndDropHostDrag(grid_location); } -bool AppsGridView::UpdateDragFromItem(Pointer pointer, +bool AppsGridView::UpdateDragFromItem(bool is_touch, const ui::LocatedEvent& event) { if (!drag_view_) return false; // Drag canceled. @@ -506,6 +511,7 @@ gfx::Point drag_point_in_grid_view; ExtractDragLocation(event.root_location(), &drag_point_in_grid_view); + const Pointer pointer = is_touch ? TOUCH : MOUSE; UpdateDrag(pointer, drag_point_in_grid_view); if (!dragging()) return false; @@ -840,6 +846,10 @@ UpdateDrag(pointer, drag_point); } +bool AppsGridView::IsDragging() const { + return dragging(); +} + bool AppsGridView::IsDraggedView(const AppListItemView* view) const { return drag_view_ == view; }
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h index 36da4ecd..3c7e18f 100644 --- a/ash/app_list/views/apps_grid_view.h +++ b/ash/app_list/views/apps_grid_view.h
@@ -14,10 +14,11 @@ #include <tuple> #include <vector> -#include "ash/app_list/model/app_list_model.h" +#include "ash/app_list/app_list_metrics.h" +#include "ash/app_list/model/app_list_item_list_observer.h" #include "ash/app_list/model/app_list_model_observer.h" #include "ash/app_list/paged_view_structure.h" -#include "ash/app_list/views/app_list_view.h" +#include "ash/app_list/views/app_list_item_view.h" #include "ash/ash_export.h" #include "ash/public/cpp/pagination/pagination_model.h" #include "base/time/time.h" @@ -26,12 +27,14 @@ #include "ui/compositor/layer_animation_observer.h" #include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/gfx/image/image_skia_operations.h" -#include "ui/views/animation/bounds_animator.h" #include "ui/views/animation/bounds_animator_observer.h" -#include "ui/views/controls/image_view.h" #include "ui/views/view.h" #include "ui/views/view_model.h" +namespace views { +class BoundsAnimator; +} // namespace views + namespace ash { namespace test { @@ -42,7 +45,9 @@ class ApplicationDragAndDropHost; class AppListConfig; class AppListItem; +class AppListItemList; class AppListItemView; +class AppListModel; class AppListViewDelegate; class AppsGridViewFolderDelegate; class ContentsView; @@ -73,6 +78,7 @@ // - The main grid of apps in the launcher // - The grid of apps in a folder class ASH_EXPORT AppsGridView : public views::View, + public AppListItemView::GridDelegate, public AppListItemListObserver, public AppListModelObserver, public ui::ImplicitAnimationObserver, @@ -130,34 +136,23 @@ // |item_list|. void SetItemList(AppListItemList* item_list); - void SetSelectedView(AppListItemView* view); - void ClearSelectedView(AppListItemView* view); - void ClearAnySelectedView(); - bool IsSelectedView(const AppListItemView* view) const; - bool has_selected_view() const { return selected_view_ != nullptr; } - AppListItemView* GetSelectedView() const; - + // AppListItemView::GridDelegate: + bool IsInFolder() const override; + void SetSelectedView(AppListItemView* view) override; + void ClearSelectedView(AppListItemView* view) override; + void ClearAnySelectedView() override; + bool IsSelectedView(const AppListItemView* view) const override; void InitiateDrag(AppListItemView* view, - Pointer pointer, const gfx::Point& location, - const gfx::Point& root_location); - - void StartDragAndDropHostDragAfterLongPress(Pointer pointer); - void TryStartDragAndDropHostDrag(Pointer pointer, - const gfx::Point& grid_location); - - // Called from AppListItemView when it receives a drag event. Returns true - // if the drag is still happening. - bool UpdateDragFromItem(Pointer pointer, const ui::LocatedEvent& event); - - // Called when the user is dragging an app. |point| is in grid view - // coordinates. - void UpdateDrag(Pointer pointer, const gfx::Point& point); - void EndDrag(bool cancel); - bool IsDraggedView(const AppListItemView* view) const; - - // Whether |view| IsDraggedView and |view| is not in it's drag start position. - bool IsDragViewMoved(const AppListItemView& view) const; + const gfx::Point& root_location) override; + void StartDragAndDropHostDragAfterLongPress() override; + bool UpdateDragFromItem(bool is_touch, + const ui::LocatedEvent& event) override; + void EndDrag(bool cancel) override; + bool IsDragging() const override; + bool IsDraggedView(const AppListItemView* view) const override; + bool IsDragViewMoved(const AppListItemView& view) const override; + const gfx::Rect& GetIdealBounds(AppListItemView* view) const override; void ClearDragState(); void SetDragViewVisible(bool visible); @@ -169,7 +164,12 @@ // Return true if the |bounds_animator_| is animating |view|. bool IsAnimatingView(AppListItemView* view); + // TODO(crbug.com/1211608): Replace these with selected_view(). + bool has_selected_view() const { return selected_view_ != nullptr; } + AppListItemView* GetSelectedView() const; + bool has_dragged_view() const { return drag_view_ != nullptr; } + // TODO(crbug.com/1211608): Remove this in favor of IsDragging(). bool dragging() const { return drag_pointer_ != NONE; } const AppListItemView* drag_view() const { return drag_view_; } @@ -200,9 +200,6 @@ // Stops the timer that triggers a page flip during a drag. void StopPageFlipTimer(); - // Returns the ideal bounds of an AppListItemView in AppsGridView coordinates. - const gfx::Rect& GetIdealBounds(AppListItemView* view) const; - // Returns the item view of the item at |index|, or nullptr if there is no // view at |index|. AppListItemView* GetItemViewAt(int index) const; @@ -278,7 +275,7 @@ // Helper for getting current app list config from the parents in the app list // view hierarchy. - const AppListConfig& GetAppListConfig() const; + const AppListConfig& GetAppListConfig() const override; // Return the view model. views::ViewModelT<AppListItemView>* view_model() { return &view_model_; } @@ -302,8 +299,6 @@ folder_delegate_ = folder_delegate; } - bool is_in_folder() const { return !!folder_delegate_; } - AppListItemView* activated_folder_item_view() const { return activated_folder_item_view_; } @@ -497,12 +492,19 @@ // currently dragged item is released. void UpdateDropTargetForReorder(const gfx::Point& point); + // Called when the user is dragging an app. |point| is in grid view + // coordinates. + void UpdateDrag(Pointer pointer, const gfx::Point& point); + // Returns true if the current drag is occurring within a certain range of the // nearest item. bool DragIsCloseToItem(); bool DragPointIsOverItem(const gfx::Point& point); + void TryStartDragAndDropHostDrag(Pointer pointer, + const gfx::Point& grid_location); + // Prepares |drag_and_drop_host_| for dragging. |grid_location| contains // the drag point in this grid view's coordinates. void StartDragAndDropHostDrag(const gfx::Point& grid_location);
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc index c1c0491..61fed871f 100644 --- a/ash/app_list/views/apps_grid_view_unittest.cc +++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -331,7 +331,7 @@ &view_origin); // AppListItemViews that belong to a folder views' AppsGridView also // need to have their x coordinate set for RTL. - if (grid_view->is_in_folder()) + if (grid_view->IsInFolder()) view_origin.set_x(grid_view->GetMirroredXInView(view_origin.x())); } if (gfx::Rect(view_origin, view->size()).Contains(point)) @@ -492,7 +492,7 @@ // Ensure that the |root_from| point is correct if RTL. root_from.set_x(apps_grid_view->GetMirroredXInView(root_from.x())); - apps_grid_view->InitiateDrag(view, pointer, root_from, root_from); + apps_grid_view->InitiateDrag(view, root_from, root_from); current_drag_location_ = root_from; // Call UpdateDrag to trigger |apps_grid_view| change to cardified_state. UpdateDrag(pointer, from, apps_grid_view); @@ -1306,7 +1306,7 @@ folder_apps_grid_view()->pagination_model(); EXPECT_EQ(1, folder_pagination_model->total_pages()); EXPECT_EQ(0, folder_pagination_model->selected_page()); - EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + EXPECT_TRUE(folder_apps_grid_view()->IsInFolder()); } TEST_P(AppsGridViewDragAndDropTest, MouseDragItemOutOfFolderFirstPage) { @@ -1365,7 +1365,7 @@ EXPECT_EQ(1, folder_apps_grid_view()->pagination_model()->selected_page()); EXPECT_EQ(4, folder_apps_grid_view()->cols()); EXPECT_EQ(4, folder_apps_grid_view()->rows_per_page()); - EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + EXPECT_TRUE(folder_apps_grid_view()->IsInFolder()); } TEST_P(AppsGridViewDragAndDropTest, MouseDragItemOutOfFolderSecondPage) { @@ -1425,7 +1425,7 @@ model_->CreateAndPopulateFolderWithApps(kTotalItems); test_api_->Update(); test_api_->PressItemAt(0); - ASSERT_TRUE(folder_apps_grid_view()->is_in_folder()); + ASSERT_TRUE(folder_apps_grid_view()->IsInFolder()); // Switch to second page. AnimateFolderViewPageFlip(1); // Fill the rest of the root grid view with new app list items. Leave 1 slot @@ -2609,7 +2609,7 @@ folder_apps_grid_view()->pagination_model(); EXPECT_EQ(1, folder_pagination_model->total_pages()); EXPECT_EQ(0, folder_pagination_model->selected_page()); - EXPECT_TRUE(folder_apps_grid_view()->is_in_folder()); + EXPECT_TRUE(folder_apps_grid_view()->IsInFolder()); } TEST_P(AppsGridViewDragAndDropTest, MoveAnItemToNewEmptyPage) {
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc index 8153fba5..18c22cd 100644 --- a/ash/app_list/views/folder_header_view.cc +++ b/ash/app_list/views/folder_header_view.cc
@@ -17,6 +17,7 @@ #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/layer.h" #include "ui/gfx/canvas.h" @@ -27,6 +28,7 @@ #include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/textfield/textfield.h" +#include "ui/views/focus/focus_manager.h" #include "ui/views/native_cursor.h" #include "ui/views/painter.h" #include "ui/views/view_targeter_delegate.h"
diff --git a/ash/app_list/views/paged_apps_grid_view.cc b/ash/app_list/views/paged_apps_grid_view.cc index d75b04f..90beb1a 100644 --- a/ash/app_list/views/paged_apps_grid_view.cc +++ b/ash/app_list/views/paged_apps_grid_view.cc
@@ -11,6 +11,7 @@ #include "ash/app_list/model/app_list_item.h" #include "ash/app_list/views/app_list_item_view.h" #include "ash/app_list/views/app_list_main_view.h" +#include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/contents_view.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_features.h" @@ -40,6 +41,7 @@ #include "ui/gfx/skia_paint_util.h" #include "ui/gfx/transform.h" #include "ui/gfx/transform_util.h" +#include "ui/views/animation/bounds_animator.h" #include "ui/views/paint_info.h" #include "ui/views/view.h" #include "ui/views/view_model_utils.h" @@ -173,9 +175,9 @@ pagination_controller_ = std::make_unique<PaginationController>( &pagination_model_, - is_in_folder() ? PaginationController::SCROLL_AXIS_HORIZONTAL - : PaginationController::SCROLL_AXIS_VERTICAL, - is_in_folder() + IsInFolder() ? PaginationController::SCROLL_AXIS_HORIZONTAL + : PaginationController::SCROLL_AXIS_VERTICAL, + IsInFolder() ? base::DoNothing() : base::BindRepeating(&AppListRecordPageSwitcherSourceByEventType), IsTabletMode()); @@ -475,7 +477,7 @@ } gfx::Insets PagedAppsGridView::GetTilePadding() const { - if (is_in_folder()) { + if (IsInFolder()) { const int tile_padding_in_folder = GetAppListConfig().grid_tile_spacing_in_folder() / 2; return gfx::Insets(-tile_padding_in_folder, -tile_padding_in_folder); @@ -520,7 +522,7 @@ void PagedAppsGridView::TotalPagesChanged(int previous_page_count, int new_page_count) { // Don't record from folder. - if (is_in_folder()) + if (IsInFolder()) return; // Initial setup for the AppList starts with -1 pages. Ignore the page count @@ -682,7 +684,7 @@ gfx::PointF root_location = event.root_location_f(); return root_location.y() - mouse_drag_start_point_.y(); }; - if (!is_in_folder() && + if (!IsInFolder() && (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_SCROLL_BEGIN) && !IsTabletMode() && ((pagination_model_.selected_page() == 0 && @@ -695,7 +697,7 @@ } void PagedAppsGridView::MaybeCreateGradientMask() { - if (!is_in_folder() && features::IsBackgroundBlurEnabled()) { + if (!IsInFolder() && features::IsBackgroundBlurEnabled()) { // TODO(newcomer): Improve implementation of the mask layer so we can // enable it on all devices https://crbug.com/765292. if (!layer()->layer_mask_layer()) { @@ -715,7 +717,7 @@ void PagedAppsGridView::StartAppsGridCardifiedView() { if (!app_list_features::IsNewDragSpecInLauncherEnabled()) return; - if (is_in_folder()) + if (IsInFolder()) return; DCHECK(!cardified_state_); StopObservingImplicitAnimations(); @@ -735,7 +737,7 @@ void PagedAppsGridView::EndAppsGridCardifiedView() { if (!app_list_features::IsNewDragSpecInLauncherEnabled()) return; - if (is_in_folder()) + if (IsInFolder()) return; DCHECK(cardified_state_); StopObservingImplicitAnimations();
diff --git a/ash/app_list/views/paged_apps_grid_view.h b/ash/app_list/views/paged_apps_grid_view.h index dfc7c5b5..81057ba 100644 --- a/ash/app_list/views/paged_apps_grid_view.h +++ b/ash/app_list/views/paged_apps_grid_view.h
@@ -11,6 +11,7 @@ #include "ash/app_list/views/apps_grid_view.h" #include "ash/ash_export.h" #include "ash/public/cpp/pagination/pagination_model_observer.h" +#include "ash/public/cpp/presentation_time_recorder.h" #include "base/memory/ref_counted.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/compositor/throughput_tracker.h"
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 0d9c57bd..c0b6ad2 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1071,18 +1071,27 @@ <message name="IDS_ASH_HOLDING_SPACE_SCREEN_CAPTURES_TITLE" desc="Title of the screen captures area in the holding space bubble."> Screen captures </message> + <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_CANCEL" desc="Title of the cancel option in the holding space item context menu."> + Cancel + </message> <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_COPY_IMAGE_TO_CLIPBOARD" desc="Title of the option to copy an image to the clipboard in the holding space item context menu."> Copy image </message> <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_HIDE_PREVIEWS" desc="Title of the option to hide previews in the holding space tray context menu."> Hide previews </message> + <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PAUSE" desc="Title of the pause option in the holding space item context menu."> + Pause + </message> <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PIN" desc="Title of the pin option in the holding space item context menu."> Pin </message> <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_REMOVE" desc="Title of the remove option in the holding space item context menu."> Remove </message> + <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_RESUME" desc="Title of the resume option in the holding space item context menu."> + Resume + </message> <message name="IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_SHOW_IN_FOLDER" desc="Title of the option to show item in its folder in the holding space item context menu."> Show in folder </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_CANCEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_CANCEL.png.sha1 new file mode 100644 index 0000000..82d9dbe --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_CANCEL.png.sha1
@@ -0,0 +1 @@ +058563d92ce33f5bb4157017f1dbc768d725c121 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PAUSE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PAUSE.png.sha1 new file mode 100644 index 0000000..aaeb508 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PAUSE.png.sha1
@@ -0,0 +1 @@ +d51be6562a5a5cf46a13d3e350ed72b107e71d69 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_RESUME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_RESUME.png.sha1 new file mode 100644 index 0000000..d2b83f5 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_RESUME.png.sha1
@@ -0,0 +1 @@ +a3bc686888118a745b504a2cb1adbcd458def5e8 \ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_notification_view.cc b/ash/capture_mode/capture_mode_notification_view.cc index 75dbae4..d77ebd3 100644 --- a/ash/capture_mode/capture_mode_notification_view.cc +++ b/ash/capture_mode/capture_mode_notification_view.cc
@@ -8,9 +8,11 @@ #include "ash/public/cpp/assistant/assistant_state.h" #include "ash/public/cpp/clipboard_history_controller.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/style/scoped_light_mode_as_default.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/events/keyboard_layout_util.h" #include "ui/gfx/paint_vector_icon.h" @@ -127,14 +129,15 @@ label->SetHorizontalAlignment(gfx::ALIGN_LEFT); label->SetEnabledColor(text_icon_color); - if (features::IsClipboardHistoryScreenshotNudgeEnabled()) { - banner_view->AddChildView(CreateClipboardShortcutView()); - layout->SetFlexForView(label, 1); + if (!Shell::Get()->tablet_mode_controller()->InTabletMode()) { + if (features::IsClipboardHistoryScreenshotNudgeEnabled()) { + banner_view->AddChildView(CreateClipboardShortcutView()); + layout->SetFlexForView(label, 1); + } + + // Notify the clipboard history of the created notification. + ClipboardHistoryController::Get()->OnScreenshotNotificationCreated(); } - - // Notify the clipboard history of the created notification. - ClipboardHistoryController::Get()->OnScreenshotNotificationCreated(); - return banner_view; }
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 998d7d8..b561b22 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -573,15 +573,6 @@ const base::Feature kPluginVmShowMicrophonePermissions{ "PluginVmShowMicrophonePermissions", base::FEATURE_ENABLED_BY_DEFAULT}; -// Controls whether to show printer statuses on the Print Preview destination -// dialog. -const base::Feature kPrinterStatusDialog{"PrinterStatusDialog", - base::FEATURE_ENABLED_BY_DEFAULT}; - -// Allows print servers to be selected when beyond a specified limit. -const base::Feature kPrintServerScaling{"PrintServerScaling", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Controls whether to enable projector. const base::Feature kProjector{"Projector", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index bc26144..814ca9c 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -254,9 +254,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPrintJobManagementApp; COMPONENT_EXPORT(ASH_CONSTANTS) -extern const base::Feature kPrintServerScaling; -COMPONENT_EXPORT(ASH_CONSTANTS) -extern const base::Feature kPrinterStatusDialog; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjector; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjectorFeaturePod; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kQuickAnswers;
diff --git a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js index 3c7cf8e..3a4b24a2 100644 --- a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js +++ b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js
@@ -196,17 +196,19 @@ } /** - * @return {!Promise<!{error: !RmadErrorCode}>} + * @return {!Promise<!StateResult>} */ updateChrome() { - return this.methods_.resolveMethod('updateChrome'); + return this.getNextStateForMethod_( + 'updateChrome', RmaState.kUpdateChrome); } /** - * @param {!RmadErrorCode} error + * @return {!Promise<!StateResult>} */ - setUpdateChromeResult(error) { - this.methods_.setResult('updateChrome', {error: error}); + updateChromeSkipped() { + return this.getNextStateForMethod_( + 'updateChromeSkipped', RmaState.kUpdateChrome); } /** @@ -263,7 +265,6 @@ * @return {!Promise<!StateResult>} */ setRsuDisableWriteProtectCode(code) { - // TODO(gavindodd): Send the code over mojo. return this.getNextStateForMethod_( 'setRsuDisableWriteProtectCode', RmaState.kEnterRSUWPDisableCode); } @@ -687,6 +688,7 @@ this.methods_.register('getCurrentChromeVersion'); this.methods_.register('checkForChromeUpdates'); this.methods_.register('updateChrome'); + this.methods_.register('updateChromeSkipped'); this.methods_.register('setSameOwner'); this.methods_.register('setDifferentOwner');
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc index 026d74b5..b7859c8 100644 --- a/ash/projector/projector_controller_impl.cc +++ b/ash/projector/projector_controller_impl.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/projector/projector_session.h" #include "ash/shell.h" #include "base/strings/utf_string_conversions.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" namespace ash { @@ -33,23 +34,15 @@ } void ProjectorControllerImpl::OnTranscription( - const std::u16string& text, - absl::optional<base::TimeDelta> start_time, - absl::optional<base::TimeDelta> end_time, - const absl::optional<std::vector<base::TimeDelta>>& word_offsets, - bool is_final) { - std::string transcript = base::UTF16ToUTF8(text); - - if (is_final && start_time.has_value() && end_time.has_value() && - word_offsets.has_value()) { - // Records final transcript. - metadata_controller_->RecordTranscription( - transcript, start_time.value(), end_time.value(), word_offsets.value()); - } - + const media::SpeechRecognitionResult& result) { // Render transcription. if (is_caption_on_) { - ui_controller_->OnTranscription(transcript, is_final); + ui_controller_->OnTranscription(result.transcription, result.is_final); + } + + if (result.is_final && result.timing_information.has_value()) { + // Records final transcript. + metadata_controller_->RecordTranscription(result); } }
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h index 2f9376e..7ce8712c 100644 --- a/ash/projector/projector_controller_impl.h +++ b/ash/projector/projector_controller_impl.h
@@ -34,12 +34,7 @@ // ProjectorController: void SetClient(ash::ProjectorClient* client) override; void OnSpeechRecognitionAvailable(bool available) override; - void OnTranscription( - const std::u16string& text, - absl::optional<base::TimeDelta> start_time, - absl::optional<base::TimeDelta> end_time, - const absl::optional<std::vector<base::TimeDelta>>& word_offsets, - bool is_final) override; + void OnTranscription(const media::SpeechRecognitionResult& result) override; void SetProjectorToolsVisible(bool is_visible) override; bool IsEligible() const override;
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc index 7370595..a99ff6d0 100644 --- a/ash/projector/projector_controller_unittest.cc +++ b/ash/projector/projector_controller_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/projector/projector_controller_impl.h" +#include <initializer_list> #include <memory> #include <string> #include <vector> @@ -15,46 +16,44 @@ #include "ash/test/ash_test_base.h" #include "base/files/file_path.h" #include "base/json/json_writer.h" -#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "base/values.h" -#include "chromeos/services/machine_learning/public/mojom/soda.mojom.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColor.h" namespace ash { namespace { - -using chromeos::machine_learning::mojom::FinalResult; -using chromeos::machine_learning::mojom::PartialResult; -using chromeos::machine_learning::mojom::SpeechRecognizerEvent; -using chromeos::machine_learning::mojom::SpeechRecognizerEventPtr; -using chromeos::machine_learning::mojom::TimingInfo; using testing::_; using testing::ElementsAre; void NotifyControllerForFinalSpeechResult(ProjectorControllerImpl* controller) { - controller->OnTranscription( - u"transcript text 1", - base::TimeDelta::FromMilliseconds(0) /* audio_start_time */, - base::TimeDelta::FromMilliseconds(3000) /* audio_end_time */, - {{base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000), - base::TimeDelta::FromMilliseconds(2500)}} /* word_offsets*/, - true /* is_final */); + media::SpeechRecognitionResult result; + result.transcription = "transcript text 1"; + result.is_final = true; + result.timing_information = media::TimingInformation(); + result.timing_information->audio_start_time = + base::TimeDelta::FromMilliseconds(0); + result.timing_information->audio_end_time = + base::TimeDelta::FromMilliseconds(3000); + + std::vector<media::HypothesisParts> hypothesis_parts; + std::string hypothesis_text[3] = {"transcript", "text", "1"}; + int hypothesis_time[3] = {1000, 2000, 2500}; + for (int i = 0; i < 3; i++) { + hypothesis_parts.emplace_back( + std::vector<std::string>({hypothesis_text[i]}), + base::TimeDelta::FromMilliseconds(hypothesis_time[i])); + } + + result.timing_information->hypothesis_parts = std::move(hypothesis_parts); + controller->OnTranscription(result); } void NotifyControllerForPartialSpeechResult( ProjectorControllerImpl* controller) { controller->OnTranscription( - u"transcript partial text 1", - base::TimeDelta::FromMilliseconds(0) /* audio_start_time */, - base::TimeDelta::FromMilliseconds(3000) /* audio_end_time */, - {{base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000), - base::TimeDelta::FromMilliseconds(2500), - base::TimeDelta::FromMilliseconds(3000)}} /* word_offsets*/, - false /* is_final */); + media::SpeechRecognitionResult("transcript partial text 1", false)); } } // namespace @@ -125,15 +124,7 @@ TEST_F(ProjectorControllerTest, OnTranscription) { // Verify that |RecordTranscription| in |ProjectorMetadataController| is // called to record the transcript. - EXPECT_CALL( - *mock_metadata_controller_, - RecordTranscription("transcript text 1", - testing::Eq(base::TimeDelta::FromMilliseconds(0)), - testing::Eq(base::TimeDelta::FromMilliseconds(3000)), - ElementsAre(base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000), - base::TimeDelta::FromMilliseconds(2500)))) - .Times(1); + EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_)).Times(1); // Verify that |OnTranscription| in |ProjectorUiController| is not called // since capton is off. EXPECT_CALL(*mock_ui_controller_, OnTranscription(_, _)).Times(0); @@ -143,8 +134,7 @@ TEST_F(ProjectorControllerTest, OnTranscriptionPartialResult) { // Verify that |RecordTranscription| in |ProjectorMetadataController| is not // called since it is not a final result. - EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_, _, _, _)) - .Times(0); + EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_)).Times(0); // Verify that |OnTranscription| in |ProjectorUiController| is not called // since caption is off. EXPECT_CALL(*mock_ui_controller_, OnTranscription(_, _)).Times(0); @@ -154,15 +144,7 @@ TEST_F(ProjectorControllerTest, OnTranscriptionCaptionOn) { // Verify that |SaveMetadata| in |ProjectorMetadataController| is called to // record the transcript. - EXPECT_CALL( - *mock_metadata_controller_, - RecordTranscription("transcript text 1", - testing::Eq(base::TimeDelta::FromMilliseconds(0)), - testing::Eq(base::TimeDelta::FromMilliseconds(3000)), - ElementsAre(base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000), - base::TimeDelta::FromMilliseconds(2500)))) - .Times(1); + EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_)).Times(1); // Verify that |OnTranscription| in |ProjectorUiController| is called since // capton is on. EXPECT_CALL(*mock_ui_controller_, OnTranscription("transcript text 1", true)) @@ -172,10 +154,9 @@ } TEST_F(ProjectorControllerTest, OnTranscriptionCaptionOnPartialResult) { - // Verify that |RecordTranscription| in |ProjectorMetadataController| is - // called. - EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_, _, _, _)) - .Times(0); + // Verify that |RecordTranscription| in |ProjectorMetadataController| is not + // called since it is not a final result. + EXPECT_CALL(*mock_metadata_controller_, RecordTranscription(_)).Times(0); // Verify that |OnTranscription| in |ProjectorUiController| is called since // capton is on. EXPECT_CALL(*mock_ui_controller_,
diff --git a/ash/projector/projector_metadata_controller.cc b/ash/projector/projector_metadata_controller.cc index 8c2d43a..81740a0 100644 --- a/ash/projector/projector_metadata_controller.cc +++ b/ash/projector/projector_metadata_controller.cc
@@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/current_thread.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" @@ -47,13 +48,13 @@ } void ProjectorMetadataController::RecordTranscription( - const std::string& transcription, - const base::TimeDelta start_time, - const base::TimeDelta end_time, - const std::vector<base::TimeDelta>& word_alignments) { + const media::SpeechRecognitionResult& speech_result) { DCHECK(metadata_); + + const auto& timing = speech_result.timing_information; metadata_->AddTranscript(std::make_unique<ProjectorTranscript>( - start_time, end_time, transcription, word_alignments)); + timing->audio_start_time, timing->audio_end_time, + speech_result.transcription, timing->hypothesis_parts.value())); } void ProjectorMetadataController::RecordKeyIdea() {
diff --git a/ash/projector/projector_metadata_controller.h b/ash/projector/projector_metadata_controller.h index 259b324..a01588cb6 100644 --- a/ash/projector/projector_metadata_controller.h +++ b/ash/projector/projector_metadata_controller.h
@@ -13,10 +13,10 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" namespace base { class FilePath; -class TimeDelta; } // namespace base namespace ash { @@ -35,10 +35,7 @@ virtual void OnRecordingStarted(); // Records the transcript in metadata. Virtual for testing. virtual void RecordTranscription( - const std::string& transcription, - const base::TimeDelta start_time, - const base::TimeDelta end_time, - const std::vector<base::TimeDelta>& word_alignments); + const media::SpeechRecognitionResult& speech_result); // Marks the next transcript as the beginning of a key idea. // Virtual for testing. virtual void RecordKeyIdea();
diff --git a/ash/projector/projector_metadata_model.cc b/ash/projector/projector_metadata_model.cc index d33eac8..64efd48 100644 --- a/ash/projector/projector_metadata_model.cc +++ b/ash/projector/projector_metadata_model.cc
@@ -18,10 +18,24 @@ constexpr base::StringPiece kStartOffsetKey = "startOffset"; constexpr base::StringPiece kEndOffsetKey = "endOffset"; constexpr base::StringPiece kTextKey = "text"; -constexpr base::StringPiece kWordAlignmentKey = "wordAlignment"; +constexpr base::StringPiece kHypothesisPartsKey = "hypothesisParts"; constexpr base::StringPiece kNameKey = "name"; constexpr base::StringPiece kCaptionsKey = "captions"; constexpr base::StringPiece kKeyIdeasKey = "tableOfContent"; +constexpr base::StringPiece kOffset = "offset"; + +base::Value HypothesisPartsToValue( + const media::HypothesisParts& hypothesis_parts) { + base::Value text_value(base::Value::Type::LIST); + for (auto& part : hypothesis_parts.text) + text_value.Append(part); + + base::Value hypothesis_part_value(base::Value::Type::DICTIONARY); + hypothesis_part_value.SetKey(kTextKey, std::move(text_value)); + hypothesis_part_value.SetIntKey( + kOffset, hypothesis_parts.hypothesis_part_offset.InMilliseconds()); + return hypothesis_part_value; +} } // namespace @@ -63,9 +77,9 @@ const base::TimeDelta start_time, const base::TimeDelta end_time, const std::string& text, - const std::vector<base::TimeDelta>& word_alignments) + const std::vector<media::HypothesisParts>& hypothesis_parts) : MetadataItem(start_time, end_time, text), - word_alignments_(word_alignments) {} + hypothesis_parts_(hypothesis_parts) {} ProjectorTranscript::~ProjectorTranscript() = default; @@ -73,10 +87,17 @@ // { // "startOffset": 100 // "endOffset": 2100 -// "text": "Today I'd like to teach..." -// "wordAlignments": [ -// 100, -// 1500, +// "text": "Today I would like to teach..." +// "hypothesisParts": [ +// { +// "text": ["Today"] +// "offset": 100 +// }, +// { +// "text": ["I"] +// "offset": 200 +// }, +// ... // ] // } // @@ -85,17 +106,19 @@ // "startOffset": INT // "endOffset": INT // "text": STRING -// "wordAlignments": LIST +// "hypothesisParts": DICT LIST +// base::Value ProjectorTranscript::ToJson() { base::Value transcript(base::Value::Type::DICTIONARY); transcript.SetIntKey(kStartOffsetKey, start_time_.InMilliseconds()); transcript.SetIntKey(kEndOffsetKey, end_time_.InMilliseconds()); transcript.SetStringKey(kTextKey, text_); - base::Value word_alignments_value(base::Value::Type::LIST); - for (auto& word_alignment : word_alignments_) - word_alignments_value.Append((int)word_alignment.InMilliseconds()); - transcript.SetKey(kWordAlignmentKey, std::move(word_alignments_value)); + base::Value hypothesis_parts_value(base::Value::Type::LIST); + for (auto& hypothesis_part : hypothesis_parts_) + hypothesis_parts_value.Append(HypothesisPartsToValue(hypothesis_part)); + + transcript.SetKey(kHypothesisPartsKey, std::move(hypothesis_parts_value)); return transcript; } @@ -134,9 +157,16 @@ // "endOffset": 2100 // "text": "Today I'd like to teach you about a central pillar of a // construction learning theory it's called the debugging Loop...", -// "wordAlignments": [ -// 100, -// 1500, +// "hypothesisParts": [ +// { +// "text" : ["Today"], +// "offset": 100, +// }, +// { +// "text": ["I"], +// "offset": 1500, +// } +// ... // ] // }], // "tableOfContent": [
diff --git a/ash/projector/projector_metadata_model.h b/ash/projector/projector_metadata_model.h index c9abc315..89a7921 100644 --- a/ash/projector/projector_metadata_model.h +++ b/ash/projector/projector_metadata_model.h
@@ -11,6 +11,7 @@ #include "ash/ash_export.h" #include "base/time/time.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" namespace base { class Value; @@ -21,9 +22,9 @@ // Base class to describe a metadata item. class MetadataItem { public: - explicit MetadataItem(const base::TimeDelta start_time, - const base::TimeDelta end_time, - const std::string& text); + MetadataItem(const base::TimeDelta start_time, + const base::TimeDelta end_time, + const std::string& text); MetadataItem(const MetadataItem&) = delete; MetadataItem& operator=(const MetadataItem&) = delete; virtual ~MetadataItem(); @@ -48,9 +49,9 @@ // Class to describe a key idea. class ASH_EXPORT ProjectorKeyIdea : public MetadataItem { public: - explicit ProjectorKeyIdea(const base::TimeDelta start_time, - const base::TimeDelta end_time, - const std::string& text = std::string()); + ProjectorKeyIdea(const base::TimeDelta start_time, + const base::TimeDelta end_time, + const std::string& text = std::string()); ProjectorKeyIdea(const ProjectorKeyIdea&) = delete; ProjectorKeyIdea& operator=(const ProjectorKeyIdea&) = delete; ~ProjectorKeyIdea() override; @@ -61,11 +62,11 @@ // Class to describe a transcription. class ASH_EXPORT ProjectorTranscript : public MetadataItem { public: - explicit ProjectorTranscript( + ProjectorTranscript( const base::TimeDelta start_time, const base::TimeDelta end_time, const std::string& text, - const std::vector<base::TimeDelta>& word_alignments); + const std::vector<media::HypothesisParts>& hypothesis_parts); ProjectorTranscript(const ProjectorTranscript&) = delete; ProjectorTranscript& operator=(const ProjectorTranscript&) = delete; ~ProjectorTranscript() override; @@ -73,14 +74,14 @@ base::Value ToJson() override; private: - std::vector<base::TimeDelta> word_alignments_; + std::vector<media::HypothesisParts> hypothesis_parts_; }; // Class to describe a projector metadata of a screencast session, including // name, transcriptions, key_ideas, etc class ASH_EXPORT ProjectorMetadata { public: - explicit ProjectorMetadata(); + ProjectorMetadata(); ProjectorMetadata(const ProjectorMetadata&) = delete; ProjectorMetadata& operator=(const ProjectorMetadata&) = delete; ~ProjectorMetadata();
diff --git a/ash/projector/projector_metadata_model_unittest.cc b/ash/projector/projector_metadata_model_unittest.cc index fd6e2f0..92f83e8b 100644 --- a/ash/projector/projector_metadata_model_unittest.cc +++ b/ash/projector/projector_metadata_model_unittest.cc
@@ -5,13 +5,16 @@ #include "ash/projector/projector_metadata_model.h" #include <memory> +#include <sstream> #include <string> #include <vector> #include "base/json/json_reader.h" #include "base/json/json_writer.h" +#include "base/logging.h" #include "base/strings/stringprintf.h" #include "base/values.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace ash { @@ -27,7 +30,12 @@ "endOffset": %i, "startOffset": %i, "text": "%s", - "wordAlignment": %s + "hypothesisParts": %s +})"; + +constexpr char kSerializedHypothesisPartTemplate[] = R"({ + "text": %s, + "offset": %i })"; void AssertSerializedString(const std::string& expected, @@ -46,13 +54,43 @@ start_offset, text.c_str()); } -std::string BuildTranscriptJson(int start_offset, - int end_offset, - const std::string& text, - const std::string& words_alignments_str) { +std::string BuildHypothesisParts( + const media::HypothesisParts& hypothesis_parts) { + std::stringstream ss; + ss << "["; + for (uint i = 0; i < hypothesis_parts.text.size(); i++) { + ss << "\"" << hypothesis_parts.text[i] << "\""; + if (i < hypothesis_parts.text.size() - 1) + ss << ", "; + } + ss << "]"; + + return base::StringPrintf( + kSerializedHypothesisPartTemplate, ss.str().c_str(), + int(hypothesis_parts.hypothesis_part_offset.InMilliseconds())); +} + +std::string BuildHypothesisPartsList( + const std::vector<media::HypothesisParts>& hypothesis_parts_vector) { + std::stringstream ss; + ss << "["; + for (uint i = 0; i < hypothesis_parts_vector.size(); i++) { + ss << BuildHypothesisParts(hypothesis_parts_vector[i]); + if (i < hypothesis_parts_vector.size() - 1) + ss << ", "; + } + ss << "]"; + return ss.str(); +} + +std::string BuildTranscriptJson( + int start_offset, + int end_offset, + const std::string& text, + const std::vector<media::HypothesisParts>& hypothesis_part) { return base::StringPrintf(kSerializedTranscriptTemplate, end_offset, start_offset, text.c_str(), - words_alignments_str.c_str()); + BuildHypothesisPartsList(hypothesis_part).c_str()); } } // namespace @@ -98,18 +136,24 @@ }; TEST_F(ProjectorTranscriptTest, ToJson) { + std::vector<media::HypothesisParts> hypothesis_parts; + hypothesis_parts.emplace_back(std::vector<std::string>({"transcript"}), + base::TimeDelta::FromMilliseconds(1000)); + hypothesis_parts.emplace_back(std::vector<std::string>({"text"}), + base::TimeDelta::FromMilliseconds(2000)); + + const auto expected_transcript = + BuildTranscriptJson(1000, 3000, "transcript text", hypothesis_parts); + ProjectorTranscript transcript( /*start_time=*/base::TimeDelta::FromMilliseconds(1000), /*end_time=*/base::TimeDelta::FromMilliseconds(3000), "transcript text", - {base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000)}); + std::move(hypothesis_parts)); std::string transcript_str; base::JSONWriter::Write(transcript.ToJson(), &transcript_str); - AssertSerializedString( - BuildTranscriptJson(1000, 3000, "transcript text", "[1000,2000]"), - transcript_str); + AssertSerializedString(expected_transcript, transcript_str); } class ProjectorMetadataTest : public testing::Test { @@ -122,22 +166,54 @@ TEST_F(ProjectorMetadataTest, Serialize) { const char kExpectedMetaData[] = R"({ - "name": "Screen Recording 1", "captions": [ { "endOffset": 3000, + "hypothesisParts": [ + { + "offset": 1000, + "text": [ + "transcript" + ] + }, + { + "offset": 2000, + "text": [ + "text" + ] + } + ], "startOffset": 1000, - "text": "transcript text", - "wordAlignment": [1000, 2000] + "text": "transcript text" }, { "endOffset": 5000, + "hypothesisParts": [ + { + "offset": 3200, + "text": [ + "transcript" + ] + }, + { + "offset": 4200, + "text": [ + "text" + ] + }, + { + "offset": 4500, + "text": [ + "2" + ] + } + ], "startOffset": 3000, - "text": "transcript text 2", - "wordAlignment":[3200, 4200, 4500] + "text": "transcript text 2" } ], - "tableOfContent":[ + "name": "Screen Recording 1", + "tableOfContent": [ { "endOffset": 5000, "startOffset": 3000, @@ -150,22 +226,31 @@ metadata.SetName("Screen Recording 1"); + std::vector<media::HypothesisParts> first_transcript; + first_transcript.emplace_back(std::vector<std::string>({"transcript"}), + base::TimeDelta::FromMilliseconds(1000)); + first_transcript.emplace_back(std::vector<std::string>({"text"}), + base::TimeDelta::FromMilliseconds(2000)); + metadata.AddTranscript(std::make_unique<ProjectorTranscript>( /*start_time=*/base::TimeDelta::FromMilliseconds(1000), /*end_time=*/base::TimeDelta::FromMilliseconds(3000), "transcript text", - std::initializer_list<base::TimeDelta>( - {base::TimeDelta::FromMilliseconds(1000), - base::TimeDelta::FromMilliseconds(2000)}))); + std::move(first_transcript))); metadata.MarkKeyIdea(); + std::vector<media::HypothesisParts> second_transcript; + second_transcript.emplace_back(std::vector<std::string>({"transcript"}), + base::TimeDelta::FromMilliseconds(3200)); + second_transcript.emplace_back(std::vector<std::string>({"text"}), + base::TimeDelta::FromMilliseconds(4200)); + second_transcript.emplace_back(std::vector<std::string>({"2"}), + base::TimeDelta::FromMilliseconds(4500)); + metadata.AddTranscript(std::make_unique<ProjectorTranscript>( /*start_time=*/base::TimeDelta::FromMilliseconds(3000), /*end_time=*/base::TimeDelta::FromMilliseconds(5000), "transcript text 2", - std::initializer_list<base::TimeDelta>( - {base::TimeDelta::FromMilliseconds(3200), - base::TimeDelta::FromMilliseconds(4200), - base::TimeDelta::FromMilliseconds(4500)}))); + std::move(second_transcript))); AssertSerializedString(kExpectedMetaData, metadata.Serialize()); }
diff --git a/ash/projector/test/mock_projector_metadata_controller.h b/ash/projector/test/mock_projector_metadata_controller.h index dcc398b..df2f491 100644 --- a/ash/projector/test/mock_projector_metadata_controller.h +++ b/ash/projector/test/mock_projector_metadata_controller.h
@@ -26,11 +26,8 @@ // ProjectorMetadataController: MOCK_METHOD0(OnRecordingStarted, void()); - MOCK_METHOD4(RecordTranscription, - void(const std::string& transcription, - const base::TimeDelta start_time, - const base::TimeDelta end_time, - const std::vector<base::TimeDelta>& word_alignments)); + MOCK_METHOD1(RecordTranscription, + void(const media::SpeechRecognitionResult& speech_result)); MOCK_METHOD0(RecordKeyIdea, void()); MOCK_METHOD1(SaveMetadata, void(const base::FilePath& video_file_path)); };
diff --git a/ash/public/cpp/projector/projector_controller.h b/ash/public/cpp/projector/projector_controller.h index df31259..e2152d4 100644 --- a/ash/public/cpp/projector/projector_controller.h +++ b/ash/public/cpp/projector/projector_controller.h
@@ -5,10 +5,9 @@ #ifndef ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_CONTROLLER_H_ #define ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_CONTROLLER_H_ -#include <vector> - #include "ash/public/cpp/ash_public_export.h" #include "base/time/time.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace ash { @@ -34,11 +33,7 @@ // Called when transcription result from mic input is ready. virtual void OnTranscription( - const std::u16string& text, - absl::optional<base::TimeDelta> start_time, - absl::optional<base::TimeDelta> end_time, - const absl::optional<std::vector<base::TimeDelta>>& word_offsets, - bool is_final) = 0; + const media::SpeechRecognitionResult& result) = 0; // Sets projector toolbar visibility. virtual void SetProjectorToolsVisible(bool is_visible) = 0;
diff --git a/ash/public/cpp/test/test_image_downloader.cc b/ash/public/cpp/test/test_image_downloader.cc index 4a881b4..2bc4401 100644 --- a/ash/public/cpp/test/test_image_downloader.cc +++ b/ash/public/cpp/test/test_image_downloader.cc
@@ -24,8 +24,10 @@ // Pretend to respond asynchronously. base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::BindOnce(std::move(callback), gfx::test::CreateImageSkia( - /*width=*/10, /*height=*/20))); + base::BindOnce(std::move(callback), + should_fail_ ? gfx::ImageSkia() + : gfx::test::CreateImageSkia( + /*width=*/10, /*height=*/20))); } } // namespace ash
diff --git a/ash/public/cpp/test/test_image_downloader.h b/ash/public/cpp/test/test_image_downloader.h index 4d4a676..168993c 100644 --- a/ash/public/cpp/test/test_image_downloader.h +++ b/ash/public/cpp/test/test_image_downloader.h
@@ -15,10 +15,15 @@ TestImageDownloader(); ~TestImageDownloader() override; + void set_should_fail(bool should_fail) { should_fail_ = should_fail; } + // ImageDownloader: void Download(const GURL& url, const net::NetworkTrafficAnnotationTag& annotation_tag, DownloadCallback callback) override; + + private: + bool should_fail_ = false; }; } // namespace ash
diff --git a/ash/public/cpp/wallpaper_controller_client.h b/ash/public/cpp/wallpaper_controller_client.h index bff60b6..9ee0aa7 100644 --- a/ash/public/cpp/wallpaper_controller_client.h +++ b/ash/public/cpp/wallpaper_controller_client.h
@@ -5,7 +5,10 @@ #ifndef ASH_PUBLIC_CPP_WALLPAPER_CONTROLLER_CLIENT_H_ #define ASH_PUBLIC_CPP_WALLPAPER_CONTROLLER_CLIENT_H_ +#include <string> + #include "ash/public/cpp/ash_public_export.h" +#include "base/callback.h" class AccountId; @@ -28,6 +31,14 @@ // Retrieves the current collection id from the Wallpaper Picker Chrome App // for migration. virtual void MigrateCollectionIdFromChromeApp() = 0; + + // Downloads and sets a new random wallpaper from the collection of the + // specified collection_id. + using DailyWallpaperUrlFetchedCallback = + base::OnceCallback<void(const std::string&)>; + virtual void FetchDailyRefreshWallpaper( + const std::string& collection_id, + DailyWallpaperUrlFetchedCallback callback) = 0; }; } // namespace ash
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index e62d97c..74d6050 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -30,6 +30,7 @@ "autoclick_scroll_right.icon", "autoclick_scroll_up.icon", "battery.icon", + "cancel.icon", "capture_mode.icon", "capture_mode_circle_stop.icon", "capture_mode_close.icon", @@ -167,6 +168,7 @@ "palette_tray_icon_magnify.icon", "palette_tray_icon_metalayer.icon", "palette_tray_icon_projector.icon", + "pause.icon", "phone_hub_battery_saver.icon", "phone_hub_battery_saver_outline.icon", "phone_hub_default_favicon.icon", @@ -188,6 +190,7 @@ "projector_selfie_cam_off.icon", "projector_selfie_cam_on.icon", "remove_circle_outline.icon", + "resume.icon", "select_to_speak_next_paragraph.icon", "select_to_speak_next_sentence.icon", "select_to_speak_pause.icon",
diff --git a/ash/resources/vector_icons/cancel.icon b/ash/resources/vector_icons/cancel.icon new file mode 100644 index 0000000..4ac87eb --- /dev/null +++ b/ash/resources/vector_icons/cancel.icon
@@ -0,0 +1,19 @@ +// 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 16, 5.41f, +LINE_TO, 14.59f, 4, +LINE_TO, 10, 8.59f, +LINE_TO, 5.41f, 4, +LINE_TO, 4, 5.41f, +LINE_TO, 8.59f, 10, +LINE_TO, 4, 14.59f, +LINE_TO, 5.41f, 16, +LINE_TO, 10, 11.41f, +LINE_TO, 14.59f, 16, +LINE_TO, 16, 14.59f, +LINE_TO, 11.41f, 10, +LINE_TO, 16, 5.41f, +CLOSE
diff --git a/ash/resources/vector_icons/pause.icon b/ash/resources/vector_icons/pause.icon new file mode 100644 index 0000000..727d1bdf --- /dev/null +++ b/ash/resources/vector_icons/pause.icon
@@ -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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 9, 5, +H_LINE_TO, 6, +V_LINE_TO, 15, +H_LINE_TO, 9, +V_LINE_TO, 5, +CLOSE, +NEW_PATH, +MOVE_TO, 14, 5, +H_LINE_TO, 11, +V_LINE_TO, 15, +H_LINE_TO, 14, +V_LINE_TO, 5, +CLOSE
diff --git a/ash/resources/vector_icons/resume.icon b/ash/resources/vector_icons/resume.icon new file mode 100644 index 0000000..e21f4a9 --- /dev/null +++ b/ash/resources/vector_icons/resume.icon
@@ -0,0 +1,10 @@ +// 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 6, 16, +LINE_TO, 16, 10, +LINE_TO, 6, 4, +V_LINE_TO, 16, +CLOSE
diff --git a/ash/system/holding_space/holding_space_view_delegate.cc b/ash/system/holding_space/holding_space_view_delegate.cc index 1ea1014..b2c4d629 100644 --- a/ash/system/holding_space/holding_space_view_delegate.cc +++ b/ash/system/holding_space/holding_space_view_delegate.cc
@@ -534,7 +534,6 @@ UpdateSelectionUi(); } -// TODO(crbug.com/1184438): Handle i18n and add icons for in-progress commands. ui::SimpleMenuModel* HoldingSpaceViewDelegate::BuildMenuModel() { context_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); @@ -575,18 +574,27 @@ } if (is_pausable) { - context_menu_model_->AddItem( - static_cast<int>(HoldingSpaceCommandId::kPauseItem), u"[I18N] Pause"); + context_menu_model_->AddItemWithIcon( + static_cast<int>(HoldingSpaceCommandId::kPauseItem), + l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_PAUSE), + ui::ImageModel::FromVectorIcon(kPauseIcon, /*color_id=*/-1, + kHoldingSpaceIconSize)); } if (is_resumable) { - context_menu_model_->AddItem( - static_cast<int>(HoldingSpaceCommandId::kResumeItem), u"[I18N] Resume"); + context_menu_model_->AddItemWithIcon( + static_cast<int>(HoldingSpaceCommandId::kResumeItem), + l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_RESUME), + ui::ImageModel::FromVectorIcon(kResumeIcon, /*color_id=*/-1, + kHoldingSpaceIconSize)); } if (is_cancelable) { - context_menu_model_->AddItem( - static_cast<int>(HoldingSpaceCommandId::kCancelItem), u"[I18N] Cancel"); + context_menu_model_->AddItemWithIcon( + static_cast<int>(HoldingSpaceCommandId::kCancelItem), + l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_CONTEXT_MENU_CANCEL), + ui::ImageModel::FromVectorIcon(kCancelIcon, /*color_id=*/-1, + kHoldingSpaceIconSize)); } // The "Pause"/"Resume"/"Cancel" commands are separated from other commands.
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc index 17680aa..177ec0e 100644 --- a/ash/system/palette/palette_tray.cc +++ b/ash/system/palette/palette_tray.cc
@@ -73,24 +73,6 @@ // Spacing between buttons in the title view (dp). constexpr int kTitleViewChildSpacing = 16; -// Returns true if the |palette_tray| is on an internal display or on every -// display if requested from the command line. -bool ShouldShowOnDisplay(PaletteTray* palette_tray) { - if (stylus_utils::IsPaletteEnabledOnEveryDisplay()) - return true; - - // |widget| is null when this function is called from PaletteTray constructor - // before it is added to a widget. - views::Widget* const widget = palette_tray->GetWidget(); - if (!widget) - return false; - - const display::Display& display = - display::Screen::GetScreen()->GetDisplayNearestWindow( - widget->GetNativeWindow()); - return display.IsInternal(); -} - class BatteryView : public views::View { public: BatteryView() { @@ -292,6 +274,33 @@ stylus_utils::IsPaletteEnabledOnEveryDisplay()); } +bool PaletteTray::ShouldShowOnDisplay() { + if (stylus_utils::IsPaletteEnabledOnEveryDisplay()) + return true; + + // |widget| is null when this function is called from PaletteTray constructor + // before it is added to a widget. + views::Widget* const widget = GetWidget(); + if (!widget) + return false; + + const display::Display& display = + display::Screen::GetScreen()->GetDisplayNearestWindow( + widget->GetNativeWindow()); + + if (!display.IsInternal()) + return false; + + for (const ui::TouchscreenDevice& device : + ui::DeviceDataManager::GetInstance()->GetTouchscreenDevices()) { + if (device.has_stylus && device.target_display_id == display.id()) { + return true; + } + } + + return display_has_stylus_for_testing_; +} + void PaletteTray::OnStylusEvent(const ui::TouchEvent& event) { if (local_state_ && !HasSeenStylus()) local_state_->SetBoolean(prefs::kHasSeenStylus, true); @@ -686,10 +695,15 @@ return local_state_ && local_state_->GetBoolean(prefs::kHasSeenStylus); } +void PaletteTray::SetDisplayHasStylusForTesting() { + display_has_stylus_for_testing_ = true; + UpdateIconVisibility(); +} + void PaletteTray::UpdateIconVisibility() { bool visible_preferred = is_palette_enabled_ && stylus_utils::HasStylusInput() && - ShouldShowOnDisplay(this) && palette_utils::IsInUserSession(); + ShouldShowOnDisplay() && palette_utils::IsInUserSession(); SetVisiblePreferred(visible_preferred); if (visible_preferred) UpdateLayout();
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h index 48dc0c3..da07ce2b 100644 --- a/ash/system/palette/palette_tray.h +++ b/ash/system/palette/palette_tray.h
@@ -39,7 +39,7 @@ // The PaletteTray shows the palette in the bottom area of the screen. This // class also controls the lifetime for all of the tools available in the // palette. PaletteTray has one instance per-display. It is only made visible if -// the display is primary and if the device has stylus hardware. +// the display is primary and the display has stylus hardware. class ASH_EXPORT PaletteTray : public TrayBackgroundView, public SessionObserver, public ShellObserver, @@ -56,8 +56,8 @@ // for determining if an event should be propagated through to the palette. bool ContainsPointInScreen(const gfx::Point& point); - // Returns true if the palette should be visible in the UI. This happens when: - // there is a stylus input, there is an internal display, and the user has not + // Returns true if the palette should be visible in the UI. This happens when + // there is a stylus input on an internal display and the user has not // disabled it in settings. This can be overridden by passing switches. bool ShouldShowPalette() const; @@ -110,6 +110,10 @@ void OnActiveToolChanged() override; aura::Window* GetWindow() override; + // Returns true if we're on an internal display with a stylus + // or on every display if requested from the command line. + bool ShouldShowOnDisplay(); + // Initializes with Shell's local state and starts to observe it. void InitializeWithLocalState(); @@ -132,6 +136,10 @@ // previously, or if the device has an internal stylus. bool HasSeenStylus(); + // Have the palette act as though it is on a display with a stylus for + // testing purposes. + void SetDisplayHasStylusForTesting(); + std::unique_ptr<PaletteToolManager> palette_tool_manager_; std::unique_ptr<PaletteWelcomeBubble> welcome_bubble_; std::unique_ptr<TrayBubbleWrapper> bubble_; @@ -150,6 +158,9 @@ // Cached palette pref value. bool is_palette_enabled_ = true; + // Whether the palette should behave as though its display has a stylus. + bool display_has_stylus_for_testing_ = false; + // Used to indicate whether the palette bubble is automatically opened by a // stylus eject event. bool is_bubble_auto_opened_ = false;
diff --git a/ash/system/palette/palette_tray_test_api.h b/ash/system/palette/palette_tray_test_api.h index 95debc4..4eff4e2 100644 --- a/ash/system/palette/palette_tray_test_api.h +++ b/ash/system/palette/palette_tray_test_api.h
@@ -36,6 +36,9 @@ palette_tray_->OnStylusStateChanged(state); } + // Have the tray act as though it is on a display with a stylus + void SetDisplayHasStylus() { palette_tray_->SetDisplayHasStylusForTesting(); } + private: PaletteTray* palette_tray_ = nullptr;
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc index 19276e93..e67d634 100644 --- a/ash/system/palette/palette_tray_unittest.cc +++ b/ash/system/palette/palette_tray_unittest.cc
@@ -80,6 +80,9 @@ palette_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->palette_tray(); test_api_ = std::make_unique<PaletteTrayTestApi>(palette_tray_); + + display::test::DisplayManagerTestApi(display_manager()) + .SetFirstDisplayAsInternalDisplay(); } PrefService* prefs() { @@ -591,6 +594,12 @@ } ~PaletteTrayTestWithInternalStylus() override = default; + // PaletteTrayTest: + void SetUp() override { + PaletteTrayTest::SetUp(); + test_api_->SetDisplayHasStylus(); + } + private: DISALLOW_COPY_AND_ASSIGN(PaletteTrayTestWithInternalStylus); }; @@ -811,6 +820,8 @@ PaletteTray* external_tray = controllers[1]->GetStatusAreaWidget()->palette_tray(); + test_api_->SetDisplayHasStylus(); + // The palette tray on the external monitor is not visible. EXPECT_TRUE(main_tray->GetVisible()); EXPECT_FALSE(external_tray->GetVisible());
diff --git a/ash/wallpaper/test_wallpaper_controller_client.cc b/ash/wallpaper/test_wallpaper_controller_client.cc index adcca05..d592485 100644 --- a/ash/wallpaper/test_wallpaper_controller_client.cc +++ b/ash/wallpaper/test_wallpaper_controller_client.cc
@@ -6,11 +6,16 @@ namespace ash { +TestWallpaperControllerClient::TestWallpaperControllerClient() = default; +TestWallpaperControllerClient::~TestWallpaperControllerClient() = default; + void TestWallpaperControllerClient::ResetCounts() { open_count_ = 0; close_preview_count_ = 0; set_default_wallpaper_count_ = 0; migrate_collection_id_from_chrome_app_count_ = 0; + fetch_daily_refresh_wallpaper_param_ = std::string(); + fetch_daily_refresh_info_fails_ = false; } // WallpaperControllerClient: @@ -32,4 +37,12 @@ migrate_collection_id_from_chrome_app_count_++; } +void TestWallpaperControllerClient::FetchDailyRefreshWallpaper( + const std::string& collection_id, + DailyWallpaperUrlFetchedCallback callback) { + fetch_daily_refresh_wallpaper_param_ = collection_id; + std::move(callback).Run(fetch_daily_refresh_info_fails_ ? std::string() + : "fun_image_url"); +} + } // namespace ash
diff --git a/ash/wallpaper/test_wallpaper_controller_client.h b/ash/wallpaper/test_wallpaper_controller_client.h index c4a5c20..6ea6452 100644 --- a/ash/wallpaper/test_wallpaper_controller_client.h +++ b/ash/wallpaper/test_wallpaper_controller_client.h
@@ -14,13 +14,11 @@ // A test wallpaper controller client class. class TestWallpaperControllerClient : public WallpaperControllerClient { public: - TestWallpaperControllerClient() = default; - + TestWallpaperControllerClient(); TestWallpaperControllerClient(const TestWallpaperControllerClient&) = delete; TestWallpaperControllerClient& operator=( const TestWallpaperControllerClient&) = delete; - - virtual ~TestWallpaperControllerClient() = default; + virtual ~TestWallpaperControllerClient(); size_t open_count() const { return open_count_; } size_t close_preview_count() const { return close_preview_count_; } @@ -30,6 +28,12 @@ size_t migrate_collection_id_from_chrome_app_count() const { return migrate_collection_id_from_chrome_app_count_; } + std::string get_fetch_daily_refresh_wallpaper_param() const { + return fetch_daily_refresh_wallpaper_param_; + } + void set_fetch_daily_refresh_info_fails(bool fails) { + fetch_daily_refresh_info_fails_ = fails; + } void ResetCounts(); @@ -39,12 +43,17 @@ void SetDefaultWallpaper(const AccountId& account_id, bool show_wallpaper) override; void MigrateCollectionIdFromChromeApp() override; + void FetchDailyRefreshWallpaper( + const std::string& collection_id, + DailyWallpaperUrlFetchedCallback callback) override; private: size_t open_count_ = 0; size_t close_preview_count_ = 0; size_t set_default_wallpaper_count_ = 0; size_t migrate_collection_id_from_chrome_app_count_ = 0; + std::string fetch_daily_refresh_wallpaper_param_; + bool fetch_daily_refresh_info_fails_ = false; }; } // namespace ash
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc index 82ed7e1..79242be 100644 --- a/ash/wallpaper/wallpaper_controller_impl.cc +++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -47,6 +47,7 @@ #include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" #include "base/path_service.h" +#include "base/rand_util.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/task/post_task.h" @@ -61,6 +62,7 @@ #include "components/user_manager/user_type.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/data_decoder/public/cpp/decode_image.h" +#include "third_party/icu/source/i18n/unicode/gregocal.h" #include "ui/compositor/layer.h" #include "ui/display/manager/display_manager.h" #include "ui/display/manager/managed_display_info.h" @@ -571,6 +573,18 @@ prefs::kSyncableWallpaperInfo); } +// Returns a suffix to be appended to the base url of Backdrop wallpapers. +std::string GetBackdropWallpaperSuffix() { + // FIFE url is used for Backdrop wallpapers and the desired image size should + // be specified. Currently we are using two times the display size. This is + // determined by trial and error and is subject to change. + // See crbug/815310 for original discussion. + gfx::Size display_size = + display::Screen::GetScreen()->GetPrimaryDisplay().size(); + return "=w" + std::to_string( + 2 * std::max(display_size.width(), display_size.height())); +} + } // namespace const char WallpaperControllerImpl::kSmallWallpaperSubDir[] = "small"; @@ -996,12 +1010,11 @@ weak_factory_.GetWeakPtr(), account_id, wallpaper_files_id, file_name, CUSTOMIZED, layout, /*show_wallpaper=*/false, image); - reload_preview_wallpaper_callback_ = - base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage, - weak_factory_.GetWeakPtr(), image, - WallpaperInfo{std::string(), layout, CUSTOMIZED, - base::Time::Now().LocalMidnight()}, - /*preview_mode=*/true, /*always_on_top=*/false); + reload_preview_wallpaper_callback_ = base::BindRepeating( + &WallpaperControllerImpl::ShowWallpaperImage, + weak_factory_.GetWeakPtr(), image, + WallpaperInfo{std::string(), layout, CUSTOMIZED, base::Time::Now()}, + /*preview_mode=*/true, /*always_on_top=*/false); // Show the preview wallpaper. reload_preview_wallpaper_callback_.Run(); } else { @@ -1018,11 +1031,12 @@ bool preview_mode, SetOnlineWallpaperCallback callback) { DCHECK(callback); + WallpaperInfo info = {url.spec(), layout, ONLINE, base::Time::Now()}; SetOnlineWallpaperIfExists( account_id, url.spec(), collection_id, layout, preview_mode, base::BindOnce(&WallpaperControllerImpl::OnAttemptSetOnlineWallpaper, - weak_factory_.GetWeakPtr(), account_id, url, layout, - preview_mode, std::move(callback))); + weak_factory_.GetWeakPtr(), account_id, info, preview_mode, + std::move(callback))); } void WallpaperControllerImpl::SetOnlineWallpaperIfExists( @@ -1310,9 +1324,9 @@ void WallpaperControllerImpl::ShowOneShotWallpaper( const gfx::ImageSkia& image) { - const WallpaperInfo info = { - std::string(), WallpaperLayout::WALLPAPER_LAYOUT_STRETCH, - WallpaperType::ONE_SHOT, base::Time::Now().LocalMidnight()}; + const WallpaperInfo info = {std::string(), + WallpaperLayout::WALLPAPER_LAYOUT_STRETCH, + WallpaperType::ONE_SHOT, base::Time::Now()}; ShowWallpaperImage(image, info, /*preview_mode=*/false, /*always_on_top=*/false); } @@ -1320,9 +1334,9 @@ void WallpaperControllerImpl::ShowAlwaysOnTopWallpaper( const base::FilePath& image_path) { is_always_on_top_wallpaper_ = true; - const WallpaperInfo info = { - std::string(), WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED, - WallpaperType::ONE_SHOT, base::Time::Now().LocalMidnight()}; + const WallpaperInfo info = {std::string(), + WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED, + WallpaperType::ONE_SHOT, base::Time::Now()}; ReparentWallpaper(GetWallpaperContainerId(locked_)); ReadAndDecodeWallpaper( base::BindOnce(&WallpaperControllerImpl::OnAlwaysOnTopWallpaperDecoded, @@ -1592,6 +1606,9 @@ wallpaper_controller_client_->MigrateCollectionIdFromChromeApp(); OnPrefChanged(); + + if (IsDailyRefreshEnabled()) + StartDailyRefreshTimer(); } void WallpaperControllerImpl::ShowDefaultWallpaperForTesting() { @@ -1613,6 +1630,15 @@ pref_change_registrar_.reset(); } +void WallpaperControllerImpl::UpdateDailyRefreshWallpaperForTesting() { + UpdateDailyRefreshWallpaper(); +} + +util::WallClockTimer& +WallpaperControllerImpl::GetDailyRefreshTimerForTesting() { + return daily_refresh_timer_; +} + void WallpaperControllerImpl::UpdateWallpaperForRootWindow( aura::Window* root_window, bool lock_state_changed, @@ -1822,7 +1848,7 @@ bool WallpaperControllerImpl::InitializeUserWallpaperInfo( const AccountId& account_id) { const WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, - DEFAULT, base::Time::Now().LocalMidnight()}; + DEFAULT, base::Time::Now()}; return SetUserWallpaperInfo(account_id, info); } @@ -1870,12 +1896,11 @@ confirm_preview_wallpaper_callback_ = base::BindOnce( &WallpaperControllerImpl::SetOnlineWallpaperImpl, weak_factory_.GetWeakPtr(), params, image, /*show_wallpaper=*/false); - reload_preview_wallpaper_callback_ = - base::BindRepeating(&WallpaperControllerImpl::ShowWallpaperImage, - weak_factory_.GetWeakPtr(), image, - WallpaperInfo{params.url, params.layout, ONLINE, - base::Time::Now().LocalMidnight()}, - /*preview_mode=*/true, /*always_on_top=*/false); + reload_preview_wallpaper_callback_ = base::BindRepeating( + &WallpaperControllerImpl::ShowWallpaperImage, + weak_factory_.GetWeakPtr(), image, + WallpaperInfo{params.url, params.layout, ONLINE, base::Time::Now()}, + /*preview_mode=*/true, /*always_on_top=*/false); // Show the preview wallpaper. reload_preview_wallpaper_callback_.Run(); } else { @@ -1888,7 +1913,7 @@ const gfx::ImageSkia& image, bool show_wallpaper) { WallpaperInfo wallpaper_info = {params.url, params.layout, ONLINE, - base::Time::Now().LocalMidnight()}; + base::Time::Now()}; if (!SetUserWallpaperInfo(params.account_id, wallpaper_info)) { LOG(ERROR) << "Setting user wallpaper info fails. This should never happen " "except in tests."; @@ -1975,7 +2000,7 @@ if (show_wallpaper) { WallpaperInfo info(cached_default_wallpaper_.file_path.value(), layout, - DEFAULT, base::Time::Now().LocalMidnight()); + DEFAULT, base::Time::Now()); ShowWallpaperImage(cached_default_wallpaper_.image, info, /*preview_mode=*/false, /*always_on_top=*/false); } @@ -2001,8 +2026,7 @@ base::FilePath(wallpaper_files_id).Append(file_name).value(); // User's custom wallpaper path is determined by relative path and the // appropriate wallpaper resolution. - WallpaperInfo info = {relative_path, layout, type, - base::Time::Now().LocalMidnight()}; + WallpaperInfo info = {relative_path, layout, type, base::Time::Now()}; if (!SetUserWallpaperInfo(account_id, info)) { LOG(ERROR) << "Setting user wallpaper info fails. This should never happen " "except in tests."; @@ -2235,7 +2259,7 @@ } else { WallpaperInfo info(device_policy_wallpaper_path_.value(), WALLPAPER_LAYOUT_CENTER_CROPPED, DEVICE, - base::Time::Now().LocalMidnight()); + base::Time::Now()); ShowWallpaperImage(image, info, /*preview_mode=*/false, /*always_on_top=*/false); } @@ -2327,22 +2351,20 @@ void WallpaperControllerImpl::OnAttemptSetOnlineWallpaper( const AccountId& account_id, - const GURL& url, - WallpaperLayout layout, + WallpaperInfo info, bool preview_mode, SetOnlineWallpaperCallback callback, bool success) { if (success) { - // Run callback and exit if setting the online wallpaper succeeded. std::move(callback).Run(true); return; } - // Try again after downloading the image. - const OnlineWallpaperParams params = {account_id, url.spec(), layout, - /*preview_mode=*/false}; + std::string url = info.location + GetBackdropWallpaperSuffix(); + const OnlineWallpaperParams params = {account_id, info.location, info.layout, + preview_mode}; ImageDownloader::Get()->Download( - url, NO_TRAFFIC_ANNOTATION_YET, + GURL(url), NO_TRAFFIC_ANNOTATION_YET, base::BindOnce(&WallpaperControllerImpl::OnOnlineWallpaperDecoded, weak_factory_.GetWeakPtr(), params, /*save_file=*/true, std::move(callback))); @@ -2373,4 +2395,95 @@ pref_service->SetString(kWallpaperCollectionId, collection_id); } +bool WallpaperControllerImpl::IsDailyRefreshEnabled() const { + return features::IsWallpaperWebUIEnabled() && !GetCollectionId().empty(); +} + +std::string WallpaperControllerImpl::GetCollectionId() const { + PrefService* pref_service = GetUserPrefServiceSyncable(GetActiveAccountId()); + CHECK(pref_service); + return pref_service->GetString(kWallpaperCollectionId); +} + +void WallpaperControllerImpl::UpdateDailyRefreshWallpaper() { + if (!IsDailyRefreshEnabled()) { + daily_refresh_timer_.Stop(); + return; + } + + // |wallpaper_controller_cient_| has a slightly shorter lifecycle than + // wallpaper controller. + if (wallpaper_controller_client_) { + wallpaper_controller_client_->FetchDailyRefreshWallpaper( + GetCollectionId(), + base::BindOnce(&WallpaperControllerImpl::SetDailyWallpaper, + weak_factory_.GetWeakPtr(), GetActiveAccountId(), + ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED, + /*preview_mode=*/false)); + } else { + StartDailyRefreshTimer(); + } +} + +void WallpaperControllerImpl::SetDailyWallpaper(const AccountId& account_id, + WallpaperLayout layout, + bool preview_mode, + const std::string& image_url) { + if (!image_url.empty()) { + SetOnlineWallpaper( + account_id, GURL(image_url), /*collection_id=*/std::string(), layout, + preview_mode, + base::BindOnce(&WallpaperControllerImpl::OnSetDailyWallpaper, + weak_factory_.GetWeakPtr())); + } else { + OnFetchDailyWallpaperFailed(); + } +} + +void WallpaperControllerImpl::OnSetDailyWallpaper(bool success) { + if (success) { + StartDailyRefreshTimer(); + } else { + OnFetchDailyWallpaperFailed(); + } +} + +void WallpaperControllerImpl::StartDailyRefreshTimer() { + using base::Time; + using base::TimeDelta; + + TimeDelta daily_refresh_delay = GetTimeToNextDailyRefreshUpdate(); + + // Add random delay within 1 hour, to prevent hot spotting, and reduce + // multiple wallpaper transitions for sync users with multiple devices + auto random_delay = TimeDelta::FromMillisecondsD( + base::RandDouble() * Time::kMillisecondsPerSecond * + Time::kSecondsPerHour); + daily_refresh_delay += random_delay; + + StartDailyRefreshTimer(daily_refresh_delay); +} + +void WallpaperControllerImpl::OnFetchDailyWallpaperFailed() { + StartDailyRefreshTimer(base::TimeDelta::FromHours(1)); +} + +void WallpaperControllerImpl::StartDailyRefreshTimer(base::TimeDelta delay) { + base::Time desired_run_time = base::Time::Now() + delay; + daily_refresh_timer_.Start( + FROM_HERE, desired_run_time, + base::BindOnce(&WallpaperControllerImpl::UpdateDailyRefreshWallpaper, + weak_factory_.GetWeakPtr())); +} + +base::TimeDelta WallpaperControllerImpl::GetTimeToNextDailyRefreshUpdate() + const { + WallpaperInfo info; + if (!GetUserWallpaperInfo(GetActiveAccountId(), &info)) + return base::TimeDelta(); + return info.date.ToDeltaSinceWindowsEpoch() - + base::Time::Now().ToDeltaSinceWindowsEpoch() + + base::TimeDelta::FromDays(1); +} + } // namespace ash
diff --git a/ash/wallpaper/wallpaper_controller_impl.h b/ash/wallpaper/wallpaper_controller_impl.h index 207e4ec..eefa609a 100644 --- a/ash/wallpaper/wallpaper_controller_impl.h +++ b/ash/wallpaper/wallpaper_controller_impl.h
@@ -26,7 +26,9 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/scoped_observation.h" +#include "base/time/time.h" #include "base/timer/timer.h" +#include "base/util/timer/wall_clock_timer.h" #include "components/account_id/account_id.h" #include "components/prefs/pref_change_registrar.h" #include "ui/compositor/compositor_lock.h" @@ -354,6 +356,10 @@ void set_bypass_decode_for_testing() { bypass_decode_for_testing_ = true; } + // Exposed for testing. + void UpdateDailyRefreshWallpaperForTesting(); + util::WallClockTimer& GetDailyRefreshTimerForTesting(); + private: FRIEND_TEST_ALL_PREFIXES(WallpaperControllerTest, BasicReparenting); FRIEND_TEST_ALL_PREFIXES(WallpaperControllerTest, @@ -558,14 +564,49 @@ void HandleWallpaperInfoSyncedIn(const AccountId& account_id, WallpaperInfo info); void OnAttemptSetOnlineWallpaper(const AccountId& account_id, - const GURL& url, - WallpaperLayout layout, + WallpaperInfo info, bool preview_mode, SetOnlineWallpaperCallback callback, bool success); - constexpr bool IsWallpaperTypeSyncable(WallpaperType type); + // If daily refresh wallpapers is enabled by the user. + bool IsDailyRefreshEnabled() const; + + // The id of the collection to query for new wallpapers when daily refresh is + // enabled. Is an empty string when it is not enabled. + std::string GetCollectionId() const; + + // With daily refresh enabled, this updates the wallpaper by asking for a + // wallpaper from within the user specified collection. + void UpdateDailyRefreshWallpaper(); + + // Callback from the client providing a url to a wallpaper from the user + // specified collection when daily refresh is enabled. If |image_url| is + // empty, fetching the url failed, and should be tried again soon. + void SetDailyWallpaper(const AccountId& account_id, + WallpaperLayout layout, + bool preview_mode, + const std::string& image_url); + + // Called after attempting to download and set a daily refresh wallpaper. + // On failure retry again in a while. + void OnSetDailyWallpaper(bool success); + + // Starts a wall clock timer, to update the wallpaper 24 hours since the last + // wallpaper was set. + void StartDailyRefreshTimer(); + + // Starts a wall clock timer to retry fetching a daily refresh wallpaper. + void OnFetchDailyWallpaperFailed(); + + // Starts a wall clock timer with the specified |delay|. + void StartDailyRefreshTimer(base::TimeDelta delay); + + // Time to next wallpaper update for daily refresh; 24 hours since last + // wallpaper set. + base::TimeDelta GetTimeToNextDailyRefreshUpdate() const; + bool locked_ = false; WallpaperMode wallpaper_mode_ = WALLPAPER_NONE; @@ -672,6 +713,8 @@ // May be null in tests. PrefService* local_state_ = nullptr; + util::WallClockTimer daily_refresh_timer_; + base::WeakPtrFactory<WallpaperControllerImpl> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(WallpaperControllerImpl);
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc index be0bf37..8bcfbddd 100644 --- a/ash/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -14,6 +14,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/test/shell_test_api.h" +#include "ash/public/cpp/test/test_image_downloader.h" #include "ash/public/cpp/wallpaper_controller_client.h" #include "ash/public/cpp/wallpaper_controller_observer.h" #include "ash/public/cpp/wallpaper_types.h" @@ -44,6 +45,7 @@ #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "base/time/time_override.h" +#include "base/util/timer/wall_clock_timer.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/user_manager/fake_user_manager.h" #include "components/user_manager/scoped_user_manager.h" @@ -299,6 +301,13 @@ base::Time::Now().LocalMidnight()); } +base::Time DayBeforeYesterdayish() { + base::TimeDelta today_delta = + base::Time::Now().LocalMidnight().ToDeltaSinceWindowsEpoch(); + base::TimeDelta yesterday_delta = today_delta - base::TimeDelta::FromDays(2); + return base::Time::FromDeltaSinceWindowsEpoch(yesterday_delta); +} + // A test implementation of the WallpaperControllerObserver interface. class TestWallpaperControllerObserver : public WallpaperControllerObserver { public: @@ -358,6 +367,8 @@ in_process_data_decoder_.service().SimulateImageDecoderCrashForTesting( true); + test_image_downloader_ = std::make_unique<TestImageDownloader>(); + controller_ = Shell::Get()->wallpaper_controller(); controller_->set_wallpaper_reload_no_delay_for_test(); @@ -369,6 +380,16 @@ custom_wallpaper_dir_.GetPath(), policy_wallpaper); } + void TearDown() override { + // Although pref services outlive wallpaper controller in the os, in ash + // tests, they are destroyed in tear down (See |AshTestHelper|). We don't + // want this timer to run a task after tear down, since it relies on a pref + // service being around. + controller_->GetDailyRefreshTimerForTesting().Stop(); + + AshTestBase::TearDown(); + } + WallpaperView* wallpaper_view() { return Shell::Get() ->GetPrimaryRootWindowController() @@ -604,6 +625,7 @@ user_manager::FakeUserManager* fake_user_manager_ = nullptr; std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; + std::unique_ptr<TestImageDownloader> test_image_downloader_; const AccountId kChildAccountId = AccountId::FromUserEmail(kChildEmail); const std::string kChildWallpaperFilesId = GetDummyFileId(kChildAccountId); @@ -1125,6 +1147,7 @@ TEST_F(WallpaperControllerTest, SetOnlineWallpaper) { SetBypassDecode(); + gfx::ImageSkia image = CreateImage(640, 480, kWallpaperColor); WallpaperLayout layout = WALLPAPER_LAYOUT_CENTER_CROPPED; SimulateUserLogin(kUser1); @@ -3010,6 +3033,8 @@ TestWallpaperControllerClient client; controller_->SetClient(&client); + SetBypassDecode(); + PutWallpaperInfoInPrefs(account_id_1, InfoWithType(CUSTOMIZED), GetLocalPrefService(), prefs::kUserWallpaperInfo); @@ -3197,4 +3222,159 @@ EXPECT_EQ("", actual); } +TEST_F(WallpaperControllerTest, UpdateDailyRefreshWallpaper) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + + std::string expected{"fun_collection"}; + SimulateUserLogin(kUser1); + + controller_->SetDailyRefreshCollectionId(expected); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + DayBeforeYesterdayish())); + + controller_->UpdateDailyRefreshWallpaperForTesting(); + EXPECT_EQ(expected, client.get_fetch_daily_refresh_wallpaper_param()); +} + +TEST_F(WallpaperControllerTest, UpdateDailyRefreshWallpaperCalledOnLogin) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + + std::string expected{"fun_collection"}; + SimulateUserLogin(kUser1); + + controller_->SetDailyRefreshCollectionId(expected); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + DayBeforeYesterdayish())); + + ClearLogin(); + SimulateUserLogin(kUser1); + + // |daily_refresh_timer_| adds a task to the sequence, as opposed to execute + // within the task that it is called in. + RunAllTasksUntilIdle(); + + EXPECT_EQ(expected, client.get_fetch_daily_refresh_wallpaper_param()); +} + +TEST_F(WallpaperControllerTest, UpdateDailyRefreshWallpaper_NotEnabled) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + + SimulateUserLogin(kUser1); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + DayBeforeYesterdayish())); + + controller_->UpdateDailyRefreshWallpaperForTesting(); + EXPECT_EQ(std::string(), client.get_fetch_daily_refresh_wallpaper_param()); +} + +TEST_F(WallpaperControllerTest, + UpdateDailyRefreshWallpaper_TimerStartsOnPrefServiceChange) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + + using base::Time; + using base::TimeDelta; + + SimulateUserLogin(kUser1); + controller_->SetDailyRefreshCollectionId("fun_collection"); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + base::Time::Now().LocalMidnight())); + + controller_->OnActiveUserPrefServiceChanged( + GetProfilePrefService(account_id_1)); + + Time run_time = + controller_->GetDailyRefreshTimerForTesting().desired_run_time(); + TimeDelta delta = run_time.ToDeltaSinceWindowsEpoch(); + + TimeDelta update_time = + Time::Now().LocalMidnight().ToDeltaSinceWindowsEpoch() + + TimeDelta::FromDays(1); + + ASSERT_GE(delta, update_time - TimeDelta::FromMinutes(1)); + ASSERT_LE(delta, + update_time + TimeDelta::FromHours(1) + TimeDelta::FromMinutes(1)); +} + +TEST_F(WallpaperControllerTest, + UpdateDailyRefreshWallpaper_RetryTimerTriggersOnFailedFetchInfo) { + using base::Time; + using base::TimeDelta; + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + client.set_fetch_daily_refresh_info_fails(true); + + SimulateUserLogin(kUser1); + controller_->SetDailyRefreshCollectionId("fun_collection"); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + DayBeforeYesterdayish())); + + controller_->UpdateDailyRefreshWallpaperForTesting(); + Time run_time = + controller_->GetDailyRefreshTimerForTesting().desired_run_time(); + TimeDelta delay = run_time - Time::Now(); + + TimeDelta one_hour = TimeDelta::FromHours(1); + // Lave a little wiggle room. + ASSERT_GE(delay, one_hour - TimeDelta::FromMinutes(1)); + ASSERT_LE(delay, one_hour + TimeDelta::FromMinutes(1)); +} + +TEST_F(WallpaperControllerTest, + UpdateDailyRefreshWallpaper_RetryTimerTriggersOnFailedFetchData) { + using base::Time; + using base::TimeDelta; + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(features::kWallpaperWebUI); + + TestWallpaperControllerClient client; + controller_->SetClient(&client); + + SimulateUserLogin(kUser1); + controller_->SetDailyRefreshCollectionId("fun_collection"); + controller_->SetUserWallpaperInfo( + account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, DAILY, + DayBeforeYesterdayish())); + + test_image_downloader_->set_should_fail(true); + + controller_->UpdateDailyRefreshWallpaperForTesting(); + + RunAllTasksUntilIdle(); + + Time run_time = + controller_->GetDailyRefreshTimerForTesting().desired_run_time(); + TimeDelta delay = run_time - Time::Now(); + + TimeDelta one_hour = TimeDelta::FromHours(1); + // Lave a little wiggle room. + ASSERT_GE(delay, one_hour - TimeDelta::FromMinutes(1)); + ASSERT_LE(delay, one_hour + TimeDelta::FromMinutes(1)); +} + } // namespace ash
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py index 48409de..42b34f2 100755 --- a/build/android/gyp/compile_resources.py +++ b/build/android/gyp/compile_resources.py
@@ -177,29 +177,10 @@ '--no-xml-namespaces', action='store_true', help='Whether to strip xml namespaces from processed xml resources.') - input_opts.add_argument( - '--short-resource-paths', - action='store_true', - help='Whether to shorten resource paths inside the apk or module.') - input_opts.add_argument( - '--strip-resource-names', - action='store_true', - help='Whether to strip resource names from the resource table of the apk ' - 'or module.') output_opts.add_argument('--arsc-path', help='Apk output for arsc format.') output_opts.add_argument('--proto-path', help='Apk output for proto format.') group = input_opts.add_mutually_exclusive_group() - group.add_argument( - '--optimized-arsc-path', - help='Output for `aapt2 optimize` for arsc format (enables the step).') - group.add_argument( - '--optimized-proto-path', - help='Output for `aapt2 optimize` for proto format (enables the step).') - input_opts.add_argument( - '--resources-config-paths', - default='[]', - help='GN list of paths to aapt2 resources config files.') output_opts.add_argument( '--info-path', help='Path to output info file for the partial apk.') @@ -222,11 +203,6 @@ output_opts.add_argument( '--emit-ids-out', help='Path to file produced by aapt2 --emit-ids.') - output_opts.add_argument( - '--resources-path-map-out-path', - help='Path to file produced by aapt2 that maps original resource paths ' - 'to shortened resource paths inside the apk or module.') - input_opts.add_argument( '--is-bundle-module', action='store_true', @@ -257,20 +233,10 @@ options.values_filter_rules) options.extra_main_r_text_files = build_utils.ParseGnList( options.extra_main_r_text_files) - options.resources_config_paths = build_utils.ParseGnList( - options.resources_config_paths) - - if options.optimized_proto_path and not options.proto_path: - # We could write to a temp file, but it's simpler to require it. - parser.error('--optimized-proto-path requires --proto-path') if not options.arsc_path and not options.proto_path: parser.error('One of --arsc-path or --proto-path is required.') - if options.resources_path_map_out_path and not options.short_resource_paths: - parser.error( - '--resources-path-map-out-path requires --short-resource-paths') - if options.package_id and options.shared_resources: parser.error('--package-id and --shared-resources are mutually exclusive') @@ -846,9 +812,6 @@ # We always create a binary arsc file first, then convert to proto, so flags # such as --shared-lib can be supported. - arsc_path = build.arsc_path - if arsc_path is None: - _, arsc_path = tempfile.mkstmp() link_command += ['-o', build.arsc_path] logging.debug('Starting: aapt2 link') @@ -896,100 +859,9 @@ build.arsc_path, build.proto_path ]) - if build.arsc_path is None: - os.remove(arsc_path) - - if options.optimized_proto_path: - _OptimizeApk(build.optimized_proto_path, options, build.temp_dir, - build.proto_path, build.r_txt_path) - elif options.optimized_arsc_path: - _OptimizeApk(build.optimized_arsc_path, options, build.temp_dir, - build.arsc_path, build.r_txt_path) - return desired_manifest_package_name -def _CombineResourceConfigs(resources_config_paths, out_config_path): - with open(out_config_path, 'w') as out_config: - for config_path in resources_config_paths: - with open(config_path) as config: - out_config.write(config.read()) - out_config.write('\n') - - -def _OptimizeApk(output, options, temp_dir, unoptimized_path, r_txt_path): - """Optimize intermediate .ap_ file with aapt2. - - Args: - output: Path to write to. - options: The command-line options. - temp_dir: A temporary directory. - unoptimized_path: path of the apk to optimize. - r_txt_path: path to the R.txt file of the unoptimized apk. - """ - optimize_command = [ - options.aapt2_path, - 'optimize', - unoptimized_path, - '-o', - output, - ] - - # Optimize the resources.arsc file by obfuscating resource names and only - # allow usage via R.java constant. - if options.strip_resource_names: - no_collapse_resources = _ExtractNonCollapsableResources(r_txt_path) - gen_config_path = os.path.join(temp_dir, 'aapt2.config') - if options.resources_config_paths: - _CombineResourceConfigs(options.resources_config_paths, gen_config_path) - with open(gen_config_path, 'a') as config: - for resource in no_collapse_resources: - config.write('{}#no_collapse\n'.format(resource)) - - optimize_command += [ - '--collapse-resource-names', - '--resources-config-path', - gen_config_path, - ] - - if options.short_resource_paths: - optimize_command += ['--shorten-resource-paths'] - if options.resources_path_map_out_path: - optimize_command += [ - '--resource-path-shortening-map', options.resources_path_map_out_path - ] - - logging.debug('Running aapt2 optimize') - build_utils.CheckOutput( - optimize_command, print_stdout=False, print_stderr=False) - - -def _ExtractNonCollapsableResources(rtxt_path): - """Extract resources that should not be collapsed from the R.txt file - - Resources of type ID are references to UI elements/views. They are used by - UI automation testing frameworks. They are kept in so that they don't break - tests, even though they may not actually be used during runtime. See - https://crbug.com/900993 - App icons (aka mipmaps) are sometimes referenced by other apps by name so must - be keps as well. See https://b/161564466 - - Args: - rtxt_path: Path to R.txt file with all the resources - Returns: - List of resources in the form of <resource_type>/<resource_name> - """ - resources = [] - _NO_COLLAPSE_TYPES = ['id', 'mipmap'] - with open(rtxt_path) as rtxt: - for line in rtxt: - for resource_type in _NO_COLLAPSE_TYPES: - if ' {} '.format(resource_type) in line: - resource_name = line.split()[2] - resources.append('{}/{}'.format(resource_type, resource_name)) - return resources - - @contextlib.contextmanager def _CreateStableIdsFile(in_path, out_path, package_name): """Transforms a file generated by --emit-ids from another package. @@ -1018,8 +890,6 @@ (options.r_text_out, build.r_txt_path), (options.arsc_path, build.arsc_path), (options.proto_path, build.proto_path), - (options.optimized_arsc_path, build.optimized_arsc_path), - (options.optimized_proto_path, build.optimized_proto_path), (options.proguard_file, build.proguard_path), (options.proguard_file_main_dex, build.proguard_main_dex_path), (options.emit_ids_out, build.emit_ids_path),
diff --git a/build/android/gyp/optimize_resources.py b/build/android/gyp/optimize_resources.py new file mode 100755 index 0000000..d3b11636 --- /dev/null +++ b/build/android/gyp/optimize_resources.py
@@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +# +# 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 argparse +import logging +import os +import sys + +from util import build_utils + + +def _ParseArgs(args): + """Parses command line options. + + Returns: + An options object as from argparse.ArgumentParser.parse_args() + """ + parser = argparse.ArgumentParser() + parser.add_argument('--aapt2-path', + required=True, + help='Path to the Android aapt2 tool.') + parser.add_argument( + '--short-resource-paths', + action='store_true', + help='Whether to shorten resource paths inside the apk or module.') + parser.add_argument( + '--strip-resource-names', + action='store_true', + help='Whether to strip resource names from the resource table of the apk ' + 'or module.') + parser.add_argument('--proto-path', + required=True, + help='Input proto format resources APK.') + parser.add_argument('--resources-config-paths', + default='[]', + help='GN list of paths to aapt2 resources config files.') + parser.add_argument('--r-text-in', + required=True, + help='Path to R.txt. Used to exclude id/ resources.') + parser.add_argument( + '--resources-path-map-out-path', + help='Path to file produced by aapt2 that maps original resource paths ' + 'to shortened resource paths inside the apk or module.') + parser.add_argument('--optimized-proto-path', + required=True, + help='Output for `aapt2 optimize`.') + options = parser.parse_args(args) + + options.resources_config_paths = build_utils.ParseGnList( + options.resources_config_paths) + + if options.resources_path_map_out_path and not options.short_resource_paths: + parser.error( + '--resources-path-map-out-path requires --short-resource-paths') + return options + + +def _CombineResourceConfigs(resources_config_paths, out_config_path): + with open(out_config_path, 'w') as out_config: + for config_path in resources_config_paths: + with open(config_path) as config: + out_config.write(config.read()) + out_config.write('\n') + + +def _ExtractNonCollapsableResources(rtxt_path): + """Extract resources that should not be collapsed from the R.txt file + + Resources of type ID are references to UI elements/views. They are used by + UI automation testing frameworks. They are kept in so that they don't break + tests, even though they may not actually be used during runtime. See + https://crbug.com/900993 + App icons (aka mipmaps) are sometimes referenced by other apps by name so must + be keps as well. See https://b/161564466 + + Args: + rtxt_path: Path to R.txt file with all the resources + Returns: + List of resources in the form of <resource_type>/<resource_name> + """ + resources = [] + _NO_COLLAPSE_TYPES = ['id', 'mipmap'] + with open(rtxt_path) as rtxt: + for line in rtxt: + for resource_type in _NO_COLLAPSE_TYPES: + if ' {} '.format(resource_type) in line: + resource_name = line.split()[2] + resources.append('{}/{}'.format(resource_type, resource_name)) + return resources + + +def _OptimizeApk(output, options, temp_dir, unoptimized_path, r_txt_path): + """Optimize intermediate .ap_ file with aapt2. + + Args: + output: Path to write to. + options: The command-line options. + temp_dir: A temporary directory. + unoptimized_path: path of the apk to optimize. + r_txt_path: path to the R.txt file of the unoptimized apk. + """ + optimize_command = [ + options.aapt2_path, + 'optimize', + unoptimized_path, + '-o', + output, + ] + + # Optimize the resources.pb file by obfuscating resource names and only + # allow usage via R.java constant. + if options.strip_resource_names: + no_collapse_resources = _ExtractNonCollapsableResources(r_txt_path) + gen_config_path = os.path.join(temp_dir, 'aapt2.config') + if options.resources_config_paths: + _CombineResourceConfigs(options.resources_config_paths, gen_config_path) + with open(gen_config_path, 'a') as config: + for resource in no_collapse_resources: + config.write('{}#no_collapse\n'.format(resource)) + + optimize_command += [ + '--collapse-resource-names', + '--resources-config-path', + gen_config_path, + ] + + if options.short_resource_paths: + optimize_command += ['--shorten-resource-paths'] + if options.resources_path_map_out_path: + optimize_command += [ + '--resource-path-shortening-map', options.resources_path_map_out_path + ] + + logging.debug('Running aapt2 optimize') + build_utils.CheckOutput(optimize_command, + print_stdout=False, + print_stderr=False) + + +def main(args): + options = _ParseArgs(args) + with build_utils.TempDir() as temp_dir: + _OptimizeApk(options.optimized_proto_path, options, temp_dir, + options.proto_path, options.r_text_in) + + +if __name__ == '__main__': + main(sys.argv[1:])
diff --git a/build/android/gyp/optimize_resources.pydeps b/build/android/gyp/optimize_resources.pydeps new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build/android/gyp/optimize_resources.pydeps
diff --git a/build/android/gyp/resources_shrinker/BUILD.gn b/build/android/gyp/resources_shrinker/BUILD.gn deleted file mode 100644 index e6381e1..0000000 --- a/build/android/gyp/resources_shrinker/BUILD.gn +++ /dev/null
@@ -1,15 +0,0 @@ -import("//build/config/android/rules.gni") - -java_binary("resources_shrinker") { - sources = [ "//build/android/gyp/resources_shrinker/Shrinker.java" ] - main_class = "build.android.gyp.resources_shrinker.Shrinker" - deps = [ - "//third_party/android_deps:com_android_tools_common_java", - "//third_party/android_deps:com_android_tools_layoutlib_layoutlib_api_java", - "//third_party/android_deps:com_android_tools_sdk_common_java", - "//third_party/android_deps:com_google_guava_guava_java", - "//third_party/android_deps:org_jetbrains_kotlin_kotlin_stdlib_java", - "//third_party/r8:r8_java", - ] - wrapper_script_name = "helper/resources_shrinker" -}
diff --git a/build/android/gyp/resources_shrinker/shrinker.pydeps b/build/android/gyp/resources_shrinker/shrinker.pydeps deleted file mode 100644 index 92c8905e..0000000 --- a/build/android/gyp/resources_shrinker/shrinker.pydeps +++ /dev/null
@@ -1,30 +0,0 @@ -# Generated by running: -# build/print_python_deps.py --root build/android/gyp/resources_shrinker --output build/android/gyp/resources_shrinker/shrinker.pydeps build/android/gyp/resources_shrinker/shrinker.py -../../../../third_party/jinja2/__init__.py -../../../../third_party/jinja2/_compat.py -../../../../third_party/jinja2/asyncfilters.py -../../../../third_party/jinja2/asyncsupport.py -../../../../third_party/jinja2/bccache.py -../../../../third_party/jinja2/compiler.py -../../../../third_party/jinja2/defaults.py -../../../../third_party/jinja2/environment.py -../../../../third_party/jinja2/exceptions.py -../../../../third_party/jinja2/filters.py -../../../../third_party/jinja2/idtracking.py -../../../../third_party/jinja2/lexer.py -../../../../third_party/jinja2/loaders.py -../../../../third_party/jinja2/nodes.py -../../../../third_party/jinja2/optimizer.py -../../../../third_party/jinja2/parser.py -../../../../third_party/jinja2/runtime.py -../../../../third_party/jinja2/tests.py -../../../../third_party/jinja2/utils.py -../../../../third_party/jinja2/visitor.py -../../../../third_party/markupsafe/__init__.py -../../../../third_party/markupsafe/_compat.py -../../../../third_party/markupsafe/_native.py -../../../gn_helpers.py -../util/__init__.py -../util/build_utils.py -../util/resource_utils.py -shrinker.py
diff --git a/build/android/gyp/resources_shrinker/shrinker.py b/build/android/gyp/unused_resources.py similarity index 65% rename from build/android/gyp/resources_shrinker/shrinker.py rename to build/android/gyp/unused_resources.py index 2800ce29..4b603d1 100755 --- a/build/android/gyp/resources_shrinker/shrinker.py +++ b/build/android/gyp/unused_resources.py
@@ -24,16 +24,21 @@ parser.add_argument( '--dependencies-res-zips', required=True, + action='append', help='Resources zip archives to investigate for unused resources.') - parser.add_argument('--dex', + parser.add_argument('--dexes', + action='append', required=True, help='Path to dex file, or zip with dex files.') parser.add_argument( '--proguard-mapping', - required=True, help='Path to proguard mapping file for the optimized dex.') - parser.add_argument('--r-text', required=True, help='Path to R.txt') - parser.add_argument('--android-manifest', + parser.add_argument('--r-texts', + action='append', + required=True, + help='Path to R.txt') + parser.add_argument('--android-manifests', + action='append', required=True, help='Path to AndroidManifest') parser.add_argument('--output-config', @@ -54,20 +59,31 @@ for dependency_res_zip in options.dependencies_res_zips: dep_subdirs += resource_utils.ExtractDeps([dependency_res_zip], temp_dir) - build_utils.CheckOutput([ - options.script, '--rtxts', options.r_text, '--manifests', - options.android_manifest, '--resourceDirs', ':'.join(dep_subdirs), - '--dex', options.dex, '--mapping', options.proguard_mapping, - '--outputConfig', options.output_config - ]) + cmd = [ + options.script, + '--rtxts', + ':'.join(options.r_texts), + '--manifests', + ':'.join(options.android_manifests), + '--resourceDirs', + ':'.join(dep_subdirs), + '--dexes', + ':'.join(options.dexes), + '--outputConfig', + options.output_config, + ] + if options.proguard_mapping: + cmd += [ + '--mapping', + options.proguard_mapping, + ] + build_utils.CheckOutput(cmd) if options.depfile: - depfile_deps = options.dependencies_res_zips + [ - options.r_text, - options.android_manifest, - options.dex, - options.proguard_mapping, - ] + depfile_deps = (options.dependencies_res_zips + options.r_texts + + options.android_manifests + options.dexes) + if options.proguard_mapping: + depfile_deps.append(options.proguard_mapping) build_utils.WriteDepfile(options.depfile, options.output_config, depfile_deps)
diff --git a/build/android/gyp/unused_resources.pydeps b/build/android/gyp/unused_resources.pydeps new file mode 100644 index 0000000..4753ec3 --- /dev/null +++ b/build/android/gyp/unused_resources.pydeps
@@ -0,0 +1,30 @@ +# Generated by running: +# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/unused_resources.pydeps build/android/gyp/unused_resources.py +../../../third_party/jinja2/__init__.py +../../../third_party/jinja2/_compat.py +../../../third_party/jinja2/asyncfilters.py +../../../third_party/jinja2/asyncsupport.py +../../../third_party/jinja2/bccache.py +../../../third_party/jinja2/compiler.py +../../../third_party/jinja2/defaults.py +../../../third_party/jinja2/environment.py +../../../third_party/jinja2/exceptions.py +../../../third_party/jinja2/filters.py +../../../third_party/jinja2/idtracking.py +../../../third_party/jinja2/lexer.py +../../../third_party/jinja2/loaders.py +../../../third_party/jinja2/nodes.py +../../../third_party/jinja2/optimizer.py +../../../third_party/jinja2/parser.py +../../../third_party/jinja2/runtime.py +../../../third_party/jinja2/tests.py +../../../third_party/jinja2/utils.py +../../../third_party/jinja2/visitor.py +../../../third_party/markupsafe/__init__.py +../../../third_party/markupsafe/_compat.py +../../../third_party/markupsafe/_native.py +../../gn_helpers.py +unused_resources.py +util/__init__.py +util/build_utils.py +util/resource_utils.py
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 489dc60..752ab30 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -966,7 +966,10 @@ parser.add_option('--resources-zip', help='Path to target\'s resources zip.') parser.add_option('--package-name', help='Java package name for these resources.') - parser.add_option('--android-manifest', help='Path to android manifest.') + parser.add_option('--android-manifest', + help='Path to the root android manifest.') + parser.add_option('--merged-android-manifest', + help='Path to the merged android manifest.') parser.add_option('--resource-dirs', action='append', default=[], help='GYP-list of resource dirs') parser.add_option( @@ -1347,6 +1350,9 @@ if options.android_manifest: deps_info['android_manifest'] = options.android_manifest + if options.merged_android_manifest: + deps_info['merged_android_manifest'] = options.merged_android_manifest + if options.bundled_srcjars: deps_info['bundled_srcjars'] = build_utils.ParseGnList( options.bundled_srcjars)
diff --git a/build/android/unused_resources/BUILD.gn b/build/android/unused_resources/BUILD.gn new file mode 100644 index 0000000..1596104 --- /dev/null +++ b/build/android/unused_resources/BUILD.gn
@@ -0,0 +1,19 @@ +# 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/rules.gni") + +java_binary("unused_resources") { + sources = [ "//build/android/unused_resources/UnusedResources.java" ] + main_class = "build.android.unused_resources.UnusedResources" + deps = [ + "//third_party/android_deps:com_android_tools_common_java", + "//third_party/android_deps:com_android_tools_layoutlib_layoutlib_api_java", + "//third_party/android_deps:com_android_tools_sdk_common_java", + "//third_party/android_deps:com_google_guava_guava_java", + "//third_party/android_deps:org_jetbrains_kotlin_kotlin_stdlib_java", + "//third_party/r8:r8_java", + ] + wrapper_script_name = "helper/unused_resources" +}
diff --git a/build/android/gyp/resources_shrinker/Shrinker.java b/build/android/unused_resources/UnusedResources.java similarity index 94% rename from build/android/gyp/resources_shrinker/Shrinker.java rename to build/android/unused_resources/UnusedResources.java index 50e2f93..6334223 100644 --- a/build/android/gyp/resources_shrinker/Shrinker.java +++ b/build/android/unused_resources/UnusedResources.java
@@ -19,7 +19,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package build.android.gyp.resources_shrinker; +package build.android.unused_resources; import static com.android.ide.common.symbols.SymbolIo.readFromAapt; import static com.android.utils.SdkUtils.endsWithIgnoreCase; @@ -44,6 +44,7 @@ import com.google.common.collect.Maps; import com.google.common.io.ByteStreams; import com.google.common.io.Closeables; +import com.google.common.io.Files; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -54,7 +55,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; @@ -77,7 +77,7 @@ - Reduce dependencies unless absolutely required. */ -public class Shrinker { +public class UnusedResources { private static final String ANDROID_RES = "android_res/"; private static final String DOT_DEX = ".dex"; private static final String DOT_CLASS = ".class"; @@ -97,9 +97,6 @@ private final StringWriter mDebugOutput; private final PrintWriter mDebugPrinter; - /** Easy way to invoke more verbose output for debugging */ - private boolean mDebug = false; - /** The computed set of unused resources */ private List<Resource> mUnused; @@ -136,8 +133,8 @@ } } - public Shrinker(Iterable<File> rTxtFiles, Iterable<File> classes, Iterable<File> manifests, - File mapping, Iterable<File> resources, File reportFile) { + public UnusedResources(Iterable<File> rTxtFiles, Iterable<File> classes, + Iterable<File> manifests, File mapping, Iterable<File> resources, File reportFile) { mRTxtFiles = rTxtFiles; mProguardMapping = mapping; mClasses = classes; @@ -213,13 +210,11 @@ throws IOException, SAXException, ParserConfigurationException { for (File resDir : resources) { File[] resourceFolders = resDir.listFiles(); - if (resourceFolders != null) { - for (File folder : resourceFolders) { - ResourceFolderType folderType = - ResourceFolderType.getFolderType(folder.getName()); - if (folderType != null) { - recordResources(folderType, folder); - } + assert resourceFolders != null : "Invalid resource directory " + resDir; + for (File folder : resourceFolders) { + ResourceFolderType folderType = ResourceFolderType.getFolderType(folder.getName()); + if (folderType != null) { + recordResources(folderType, folder); } } } @@ -392,7 +387,7 @@ @Override public void referencedInt(int value) { - Shrinker.this.referencedInt("dex", value, file, name); + UnusedResources.this.referencedInt("dex", value, file, name); } @Override @@ -502,8 +497,7 @@ private void referencedInt(String context, int value, File file, String currentClass) { Resource resource = mModel.getResource(value); - if (ResourceUsageModel.markReachable(resource) && mDebug) { - assert mDebugPrinter != null : "mDebug is true, but mDebugPrinter is null."; + if (ResourceUsageModel.markReachable(resource) && mDebugPrinter != null) { mDebugPrinter.println("Marking " + resource + " reachable: referenced from " + context + " in " + file + ":" + currentClass); } @@ -563,7 +557,7 @@ .map(s -> new File(s)) .collect(Collectors.toList()); break; - case "--dex": + case "--dexes": classes = Arrays.stream(args[i + 1].split(":")) .map(s -> new File(s)) .collect(Collectors.toList()); @@ -591,9 +585,10 @@ throw new IllegalArgumentException(args[i] + " is not a valid arg."); } } - Shrinker shrinker = new Shrinker(rTxtFiles, classes, manifests, mapping, resources, log); - shrinker.analyze(); - shrinker.close(); - shrinker.emitConfig(configPath); + UnusedResources unusedResources = + new UnusedResources(rTxtFiles, classes, manifests, mapping, resources, log); + unusedResources.analyze(); + unusedResources.close(); + unusedResources.emitConfig(configPath); } }
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 11eb48c..3486660 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -360,6 +360,12 @@ args += [ "--treat-as-locale-paks" ] } + if (defined(invoker.merged_android_manifest)) { + args += [ + "--merged-android-manifest", + rebase_path(invoker.merged_android_manifest, root_build_dir), + ] + } if (defined(invoker.android_manifest)) { inputs += [ invoker.android_manifest ] args += [ @@ -2249,29 +2255,15 @@ # Use resource IDs provided by another APK target when compiling resources # (via. "aapt2 link --stable-ids") # - # short_resource_paths: (optional) - # Rename the paths within a the apk to be randomly generated short - # strings to reduce binary size. - # - # strip_resource_names: (optional) - # Strip resource names from the resources table of the apk. # # Output variables: # arsc_output: Path to output .ap_ file (optional). # # proto_output: Path to output .proto.ap_ file (optional). # - # optimized_arsc_output: Path to optimized .ap_ file (optional). - # - # optimized_proto_output: Path to optimized .proto.ap_ file (optional). - # # r_text_out_path: (optional): # Path for the corresponding generated R.txt file. # - # resources_path_map_out_path: (optional): - # Path for the generated map between original resource paths and - # shortend resource paths. - # # proguard_file: (optional) # Path to proguard configuration file for this apk target. # @@ -2301,9 +2293,6 @@ if (defined(invoker.arsc_output)) { _arsc_output = invoker.arsc_output } - if (defined(invoker.optimized_arsc_output)) { - _optimized_arsc_output = invoker.optimized_arsc_output - } _final_srcjar_path = "${target_gen_dir}/${target_name}.srcjar" _script = "//build/android/gyp/compile_resources.py" @@ -2371,36 +2360,6 @@ rebase_path(invoker.size_info_path, root_build_dir), ] } - if (defined(_optimized_arsc_output)) { - _outputs += [ _optimized_arsc_output ] - _args += [ - "--optimized-arsc-path", - rebase_path(_optimized_arsc_output, root_build_dir), - ] - } - if (defined(invoker.optimized_proto_output)) { - _outputs += [ invoker.optimized_proto_output ] - _args += [ - "--optimized-proto-path", - rebase_path(invoker.optimized_proto_output, root_build_dir), - ] - } - if (defined(invoker.resources_config_paths)) { - _inputs += invoker.resources_config_paths - _rebased_resource_configs = - rebase_path(invoker.resources_config_paths, root_build_dir) - _args += [ "--resources-config-paths=${_rebased_resource_configs}" ] - } - if (defined(invoker.short_resource_paths) && invoker.short_resource_paths) { - _args += [ "--short-resource-paths" ] - if (defined(invoker.resources_path_map_out_path)) { - _outputs += [ invoker.resources_path_map_out_path ] - _args += [ - "--resources-path-map-out-path", - rebase_path(invoker.resources_path_map_out_path, root_build_dir), - ] - } - } if (defined(invoker.r_java_root_package_name)) { _args += [ @@ -2409,10 +2368,6 @@ ] } - if (defined(invoker.strip_resource_names) && invoker.strip_resource_names) { - _args += [ "--strip-resource-names" ] - } - # Useful to have android:debuggable in the manifest even for Release # builds. Just omit it for officai if (debuggable_apks) { @@ -2639,35 +2594,115 @@ } } + # A template that is used to optimize compiled resources using aapt2 optimize. + # + # proto_input_path: + # Path to input compiled .proto.ap_ file. + # + # short_resource_paths: (optional) + # Rename the paths within a the apk to be randomly generated short + # strings to reduce binary size. + # + # strip_resource_names: (optional) + # Strip resource names from the resources table of the apk. + # + # resources_configs_paths: (optional) + # List of resource configs to use for optimization. + # + # optimized_proto_output: + # Path to output optimized .proto.ap_ file. + # + # resources_path_map_out_path: (optional): + # Path for the generated map between original resource paths and + # shortened resource paths. + template("optimize_resources") { + forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) + action_with_pydeps(target_name) { + forward_variables_from(invoker, [ "deps" ]) + script = "//build/android/gyp/optimize_resources.py" + outputs = [ invoker.optimized_proto_output ] + inputs = [ + android_sdk_tools_bundle_aapt2, + invoker.r_text_path, + invoker.proto_input_path, + ] + args = [ + "--aapt2-path", + rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir), + "--r-text-in", + rebase_path(invoker.r_text_path, root_build_dir), + "--proto-path", + rebase_path(invoker.proto_input_path, root_build_dir), + "--optimized-proto-path", + rebase_path(invoker.optimized_proto_output, root_build_dir), + ] + + if (defined(invoker.resources_config_paths)) { + inputs += invoker.resources_config_paths + _rebased_resource_configs = + rebase_path(invoker.resources_config_paths, root_build_dir) + args += [ "--resources-config-paths=${_rebased_resource_configs}" ] + } + + if (defined(invoker.short_resource_paths) && + invoker.short_resource_paths) { + args += [ "--short-resource-paths" ] + if (defined(invoker.resources_path_map_out_path)) { + outputs += [ invoker.resources_path_map_out_path ] + args += [ + "--resources-path-map-out-path", + rebase_path(invoker.resources_path_map_out_path, root_build_dir), + ] + } + } + + if (defined(invoker.strip_resource_names) && + invoker.strip_resource_names) { + args += [ "--strip-resource-names" ] + } + } + } + + # A template that is used to find unused resources. template("unused_resources") { - _rebased_build_config = rebase_path(invoker.build_config, root_build_dir) - _shrinker_dep = "//build/android/gyp/resources_shrinker:resources_shrinker" - _shrinker_script = "$root_build_dir/bin/helper/resources_shrinker" action_with_pydeps(target_name) { forward_variables_from(invoker, TESTONLY_AND_VISIBILITY + [ "deps" ]) - script = "//build/android/gyp/resources_shrinker/shrinker.py" - inputs = [ - invoker.build_config, - invoker.proguard_mapping_path, - _shrinker_script, - ] + script = "//build/android/gyp/unused_resources.py" + depfile = "$target_gen_dir/${target_name}.d" + _unused_resources_script = "$root_build_dir/bin/helper/unused_resources" + inputs = [ _unused_resources_script ] outputs = [ invoker.output_config ] if (!defined(deps)) { deps = [] } - deps += [ _shrinker_dep ] + deps += [ "//build/android/unused_resources:unused_resources" ] args = [ "--script", - rebase_path(_shrinker_script, root_build_dir), - "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", - "--proguard-mapping", - rebase_path(invoker.proguard_mapping_path, root_build_dir), - "--r-text=@FileArg($_rebased_build_config:deps_info:r_text_path)", - "--dex=@FileArg($_rebased_build_config:final_dex:path)", - "--android-manifest=@FileArg($_rebased_build_config:deps_info:android_manifest)", + rebase_path(_unused_resources_script, root_build_dir), "--output-config", rebase_path(invoker.output_config, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), ] + + if (defined(invoker.proguard_mapping_path)) { + inputs += [ invoker.proguard_mapping_path ] + args += [ + "--proguard-mapping", + rebase_path(invoker.proguard_mapping_path, root_build_dir), + ] + } + + foreach(_build_config, invoker.module_build_configs) { + inputs += [ _build_config ] + _rebased_build_config = rebase_path(_build_config, root_build_dir) + args += [ + "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", + "--r-texts=@FileArg($_rebased_build_config:deps_info:r_text_path)", + "--dexes=@FileArg($_rebased_build_config:final_dex:path)", + "--android-manifests=@FileArg($_rebased_build_config:deps_info:merged_android_manifest)", + ] + } } } @@ -3622,6 +3657,7 @@ [ "android_manifest", "android_manifest_dep", + "merged_android_manifest", "final_dex_path", "loadable_modules", "native_lib_placeholders",
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index d33240d..bab3386 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -2077,6 +2077,8 @@ # uncompress_dex: Store final .dex files uncompressed in the apk. # strip_resource_names: True if resource names should be stripped from the # resources.arsc file in the apk or module. + # strip_unused_resources: True if unused resources should be stripped from + # the apk or module. # short_resource_paths: True if resource paths should be shortened in the # apk or module. # resources_config_paths: List of paths to the aapt2 optimize config files @@ -2163,20 +2165,8 @@ if (!_is_bundle_module) { _final_apk_path = invoker.final_apk_path - _final_rtxt_path = "${_final_apk_path}.R.txt" } - _short_resource_paths = - defined(invoker.short_resource_paths) && invoker.short_resource_paths && - enable_arsc_obfuscation - _strip_resource_names = - defined(invoker.strip_resource_names) && invoker.strip_resource_names && - enable_arsc_obfuscation - _optimize_resources = _strip_resource_names || _short_resource_paths - - if (!_is_bundle_module && _short_resource_paths) { - _final_pathmap_path = "${_final_apk_path}.pathmap.txt" - } _res_size_info_path = "$target_out_dir/$target_name.ap_.info" if (!_is_bundle_module) { _final_apk_path_no_ext_list = @@ -2193,20 +2183,12 @@ if (_is_bundle_module) { # Path to the intermediate proto-format resources zip file. _proto_resources_path = "$target_out_dir/$target_name.proto.ap_" - if (_optimize_resources) { - _optimized_proto_resources_path = - "$target_out_dir/$target_name.optimized.proto.ap_" - } } else { # resource_sizes.py needs to be able to find the unpacked resources.arsc # file based on apk name to compute normatlized size. _resource_sizes_arsc_path = "$root_out_dir/arsc/" + rebase_path(_final_apk_path_no_ext, root_build_dir) + ".ap_" - if (_optimize_resources) { - _optimized_arsc_resources_path = - "$target_out_dir/$target_name.optimized.ap_" - } } if (defined(invoker.version_code)) { @@ -2449,11 +2431,6 @@ "${_shared_resources_allowlist_target}__compile_resources" } - if (_short_resource_paths) { - _resources_path_map_out_path = - "${target_gen_dir}/${_template_name}_resources_path_map.txt" - } - _compile_resources_target = "${_template_name}__compile_resources" _compile_resources_rtxt_out = "${target_gen_dir}/${_compile_resources_target}_R.txt" @@ -2479,13 +2456,10 @@ "resource_exclusion_exceptions", "resource_exclusion_regex", "resource_values_filter_rules", - "resources_config_paths", "shared_resources", "shared_resources_allowlist_locales", "uses_split", ]) - short_resource_paths = _short_resource_paths - strip_resource_names = _strip_resource_names android_manifest = _android_manifest android_manifest_dep = ":$_merge_manifest_target" version_code = _version_code @@ -2511,9 +2485,6 @@ if (_enable_main_dex_list) { proguard_file_main_dex = _generated_proguard_main_dex_config } - if (_short_resource_paths) { - resources_path_map_out_path = _resources_path_map_out_path - } build_config = _build_config build_config_dep = ":$_build_config_target" @@ -2550,9 +2521,6 @@ if (_is_bundle_module) { is_bundle_module = true proto_output = _proto_resources_path - if (_optimize_resources) { - optimized_proto_output = _optimized_proto_resources_path - } if (defined(invoker.base_module_target)) { include_resource = @@ -2560,8 +2528,6 @@ "/" + get_label_info(invoker.base_module_target, "name") + ".ap_" _link_against = invoker.base_module_target } - } else if (_optimize_resources) { - optimized_arsc_output = _optimized_arsc_resources_path } if (defined(_link_against)) { @@ -2584,6 +2550,55 @@ } _srcjar_deps += [ ":$_compile_resources_target" ] + # We don't ship apks anymore, only optimize bundle builds + if (_is_bundle_module) { + _short_resource_paths = + defined(invoker.short_resource_paths) && + invoker.short_resource_paths && enable_arsc_obfuscation + _strip_resource_names = + defined(invoker.strip_resource_names) && + invoker.strip_resource_names && enable_arsc_obfuscation + _strip_unused_resources = defined(invoker.strip_unused_resources) && + invoker.strip_unused_resources + _optimize_resources = _strip_resource_names || _short_resource_paths || + _strip_unused_resources + } + + if (_is_bundle_module && _optimize_resources) { + _optimized_proto_resources_path = + "$target_out_dir/$target_name.optimized.proto.ap_" + if (_short_resource_paths) { + _resources_path_map_out_path = + "${target_gen_dir}/${_template_name}_resources_path_map.txt" + } + _optimize_resources_target = "${_template_name}__optimize_resources" + optimize_resources(_optimize_resources_target) { + deps = _deps + [ ":$_compile_resources_target" ] + short_resource_paths = _short_resource_paths + strip_resource_names = _strip_resource_names + if (_short_resource_paths) { + resources_path_map_out_path = _resources_path_map_out_path + } + r_text_path = _compile_resources_rtxt_out + proto_input_path = _proto_resources_path + optimized_proto_output = _optimized_proto_resources_path + if (_strip_unused_resources) { + # These need to be kept in sync with the target names + output paths + # in the android_app_bundle template. + _unused_resources_target = "${_template_name}__unused_resources" + _unused_resources_config_path = + "$target_gen_dir/${_template_name}_unused_resources.config" + resources_config_paths = [ _unused_resources_config_path ] + deps += [ ":$_unused_resources_target" ] + } else { + resources_config_paths = [] + } + if (defined(invoker.resources_config_paths)) { + resources_config_paths += invoker.resources_config_paths + } + } + } + if (defined(_resource_sizes_arsc_path)) { _copy_arsc_target = "${_template_name}__copy_arsc" copy(_copy_arsc_target) { @@ -2596,36 +2611,6 @@ _final_deps += [ ":$_copy_arsc_target" ] } - if (!_is_bundle_module) { - # Output the R.txt file to a more easily discoverable location for - # archiving. This is necessary when stripping resource names so that we - # have an archive of resource names to ids for shipped apks (for - # debugging purposes). We copy the file rather than change the location - # of the original because other targets rely on the location of the R.txt - # file. - _copy_rtxt_target = "${_template_name}__copy_rtxt" - copy(_copy_rtxt_target) { - deps = [ ":$_compile_resources_target" ] - sources = [ _compile_resources_rtxt_out ] - outputs = [ _final_rtxt_path ] - } - _final_deps += [ ":$_copy_rtxt_target" ] - - if (_short_resource_paths) { - # Do the same for path map - _copy_pathmap_target = "${_template_name}__copy_pathmap" - copy(_copy_pathmap_target) { - deps = [ ":$_compile_resources_target" ] - sources = [ _resources_path_map_out_path ] - outputs = [ _final_pathmap_path ] - - # The monochrome_public_apk_checker test needs pathmap when run on swarming. - data = [ _final_pathmap_path ] - } - _final_deps += [ ":$_copy_pathmap_target" ] - } - } - _generate_native_libraries_java = (!_is_bundle_module || _is_base_module) && (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) && @@ -2788,6 +2773,7 @@ supports_android = true requires_android = true srcjar_deps = _srcjar_deps + merged_android_manifest = _android_manifest if (defined(_final_dex_path)) { final_dex_path = _final_dex_path } @@ -3055,6 +3041,9 @@ ":$_build_config_target", ":$_compile_resources_target", ] + _all_native_libs_deps + if (_optimize_resources) { + _final_deps += [ ":$_optimize_resources_target" ] + } if (defined(_final_dex_target_dep)) { not_needed([ "_final_dex_target_dep" ]) } @@ -3198,11 +3187,7 @@ deps += [ _final_dex_target_dep ] } - if (_optimize_resources) { - packaged_resources_path = _optimized_arsc_resources_path - } else { - packaged_resources_path = _arsc_resources_path - } + packaged_resources_path = _arsc_resources_path if (defined(_native_libs_filearg)) { native_libs_filearg = _native_libs_filearg @@ -3481,7 +3466,6 @@ "resource_exclusion_regex", "resource_ids_provider_dep", "resource_values_filter_rules", - "resources_config_paths", "require_native_mocks", "secondary_abi_loadable_modules", "secondary_abi_shared_libraries", @@ -3490,13 +3474,11 @@ "shared_resources", "shared_resources_allowlist_locales", "shared_resources_allowlist_target", - "short_resource_paths", "sources", "srcjar_deps", "static_library_dependent_targets", "static_library_provider", "static_library_synchronized_proguard", - "strip_resource_names", "target_sdk_version", "testonly", "uncompress_dex", @@ -3624,6 +3606,7 @@ "static_library_provider", "static_library_synchronized_proguard", "strip_resource_names", + "strip_unused_resources", "target_sdk_version", "testonly", "uncompress_shared_libraries", @@ -4732,6 +4715,7 @@ _all_create_module_targets = [] _all_module_zip_paths = [] _all_module_build_configs = [] + _all_module_unused_resources_deps = [] foreach(_module, _modules) { _module_target = _module.module_target _module_build_config = _module.build_config @@ -4750,7 +4734,6 @@ # this file *must* be named ${_module.name}.zip _create_module_target = "${_target_name}__${_module.name}__create" _module_zip_path = "$target_gen_dir/$target_name/${_module.name}.zip" - create_android_app_bundle_module(_create_module_target) { forward_variables_from(invoker, [ @@ -4801,6 +4784,27 @@ ] _all_module_zip_paths += [ _module_zip_path ] _all_module_build_configs += [ _module_build_config ] + _all_module_unused_resources_deps += [ + "${_module_target}__compile_resources", + _dex_target_for_module, + _module_build_config_target, + ] + } + if (defined(invoker.strip_unused_resources) && + invoker.strip_unused_resources) { + # Resources only live in the base module so we define the unused resources + # target only on the base module target. + _unused_resources_target = "${_base_target_name}__unused_resources" + _unused_resources_config = + "${_base_target_gen_dir}/${_base_target_name}_unused_resources.config" + unused_resources(_unused_resources_target) { + deps = _all_module_unused_resources_deps + module_build_configs = _all_module_build_configs + if (_proguard_enabled) { + proguard_mapping_path = _proguard_mapping_path + } + output_config = _unused_resources_config + } } _all_rebased_module_zip_paths =
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index b1ae5bed..cc39756 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -4.20210603.0.1 +4.20210603.4.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index b1ae5bed..cc39756 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4.20210603.0.1 +4.20210603.4.1
diff --git a/buildtools/reclient_cfgs/OWNERS b/buildtools/reclient_cfgs/OWNERS new file mode 100644 index 0000000..ae14021 --- /dev/null +++ b/buildtools/reclient_cfgs/OWNERS
@@ -0,0 +1,5 @@ +abdelaal@google.com +msavigny@google.com +tikuta@google.com +ukai@google.com +yyanagisawa@google.com
diff --git a/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows.cfg b/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows.cfg index 95d0386..1448dfa 100644 --- a/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows.cfg +++ b/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows.cfg
@@ -1,4 +1,4 @@ -platform=container-image=docker://gcr.io/goma-foundry-experiments/re-client/chromium-win-cross@sha256:962da618112151bdf80418e55914a1e16ab64cea3846d23642c8fd191740d428,OSFamily=Linux +platform=container-image=docker://gcr.io/goma-foundry-experiments/re-client/chromium-win-cross@sha256:f18b6081b813cb64beab5c6d9b6f5608daffbc4abde6137a5a2185779da6332d,OSFamily=Linux server_address=pipe://reproxy.pipe labels=type=compile,compiler=clang-cl,lang=cpp exec_strategy=remote_local_fallback
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc index 4a479a8..d0dbbf18 100644 --- a/cc/paint/oop_pixeltest.cc +++ b/cc/paint/oop_pixeltest.cc
@@ -1798,7 +1798,7 @@ avg_error = std::max(is_record_filter ? 50.f : 2.f, avg_error); } else if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kPerspective) { error_pixels_percentage = - std::max(is_record_filter ? 12.f : 4.f, error_pixels_percentage); + std::max(is_record_filter ? 13.f : 4.f, error_pixels_percentage); max_abs_error = std::max(is_record_filter ? 255 : 36, max_abs_error); avg_error = std::max(is_record_filter ? 60.f : 36.f, avg_error); }
diff --git a/chrome/VERSION b/chrome/VERSION index cc52d18..ad8cd96 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=93 MINOR=0 -BUILD=4532 +BUILD=4533 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 4a99266..1aad36e 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -581,6 +581,7 @@ deps += web_feed_deps srcjar_deps = [ + ":autofill_verification_status_generated_enum", ":chrome_android_java_enums_srcjar", ":chrome_android_java_google_api_keys_srcjar", ":chrome_strict_mode_switch", @@ -779,6 +780,10 @@ ] } +java_cpp_enum("autofill_verification_status_generated_enum") { + sources = [ "//components/autofill/core/browser/data_model/autofill_structured_address_component.h" ] +} + java_cpp_enum("chrome_android_java_enums_srcjar") { sources = [ "//chrome/browser/android/customtabs/detached_resource_request.h",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index c485c30a..c5089dd 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -179,10 +179,23 @@ png_to_webp = !is_java_debug } - # Removes metadata needed for Resources.getIdentifier("resource_name"). - strip_resource_names = !is_java_debug + # We only optimize resources for bundles since APKs are not shipped. + # Resources only live in the base module atm as such we only need to set + # these on the base module + if (_is_bundle) { + # Removes metadata needed for Resources.getIdentifier("resource_name"). + strip_resource_names = !is_java_debug - short_resource_paths = true + # Shortens resource file names in apk eg: res/drawable/button.xml -> res/a.xml + short_resource_paths = true + + # Removes unused resources from the apk. Only enabled on official builds + # since it adds a slow step and serializes the build graph causing fewer + # expensive tasks (eg: proguarding, resource optimization) to be run in + # parallel by adding dependencies between them (adds around 10-20 + # seconds on my machine). + strip_unused_resources = is_official_build + } if (!defined(aapt_locale_allowlist)) { # Include resource strings files only for supported locales. @@ -539,13 +552,16 @@ } } - # Resources config for blocklisting resource names from obfuscation - resources_config_paths = [ - "//android_webview/aapt2.config", - "//chrome/android/aapt2.config", - ] - if (defined(invoker.resources_config_paths)) { - resources_config_paths += invoker.resources_config_paths + # We only optimize resources in bundles. + if (_is_bundle_module) { + # Resources config for blocklisting resource names from obfuscation + resources_config_paths = [ + "//android_webview/aapt2.config", + "//chrome/android/aapt2.config", + ] + if (defined(invoker.resources_config_paths)) { + resources_config_paths += invoker.resources_config_paths + } } if (defined(invoker.never_incremental)) {
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected index 55b8825..236f59a 100644 --- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected +++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -646,16 +646,6 @@ <init>(); } -# File: obj/third_party/androidx/androidx_startup_startup_runtime_java/proguard.txt -# This Proguard rule ensures that ComponentInitializers are are neither shrunk nor obfuscated. -# This is because they are discovered and instantiated during application initialization. --keep class * extends androidx.startup.Initializer { - # Keep the public no-argument constructor while allowing other methods to be optimized. - <init>(); -} - --assumenosideeffects class androidx.startup.StartupLogger - # File: obj/third_party/androidx/androidx_transition_transition_java/proguard.txt # Copyright (C) 2017 The Android Open Source Project #
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java index a6f57fd8..fcd95a59 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -48,6 +48,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeoutException; /** * Integration tests of the {@link StartSurface} for cases where there are no tabs. See {@link @@ -112,7 +113,7 @@ @Feature({"StartSurface"}) // clang-format off @CommandLineFlags.Add({BASE_PARAMS + "/single"}) - public void testShow_SingleAsHomepage_NoTabs() { + public void testShow_SingleAsHomepage_NoTabs() throws TimeoutException { // clang-format on CriteriaHelper.pollUiThread( ()
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 52550a3..09c60b0 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
@@ -38,8 +38,6 @@ import static org.chromium.chrome.test.util.ViewUtils.waitForView; import android.os.Build; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.support.test.InstrumentationRegistry; import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import android.support.test.runner.lifecycle.Stage; @@ -232,8 +230,13 @@ mLayoutChangedCallbackHelper.notifyCalled(); } }; - mActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver( - (obs) -> { obs.addObserver(mLayoutObserver); }); + mActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver((manager) -> { + if (manager.getActiveLayout() != null) { + mCurrentlyActiveLayout = manager.getActiveLayout().getLayoutType(); + mLayoutChangedCallbackHelper.notifyCalled(); + } + manager.addObserver(mLayoutObserver); + }); } @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 8f84d93..0f4d292 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -667,8 +667,9 @@ if (getCompositorViewHolder() == null) return null; return getCompositorViewHolder().getLayerTitleCache(); }, - mOverviewModeBehaviorSupplier, mLayoutStateProviderOneshotSupplier, + mOverviewModeBehaviorSupplier, mRootUiCoordinator::getTopUiThemeColorProvider); + mLayoutStateProviderOneshotSupplier.set(mLayoutManager); // clang-format on mOverviewModeController = mLayoutManager; } @@ -686,8 +687,9 @@ if (getCompositorViewHolder() == null) return null; return getCompositorViewHolder().getLayerTitleCache(); }, - mOverviewModeBehaviorSupplier, mLayoutStateProviderOneshotSupplier, + mOverviewModeBehaviorSupplier, mRootUiCoordinator::getTopUiThemeColorProvider); + mLayoutStateProviderOneshotSupplier.set(mLayoutManager); // clang-format on mOverviewModeController = mLayoutManager; } @@ -2416,7 +2418,8 @@ @Override public boolean dispatchKeyEvent(KeyEvent event) { - Boolean result = KeyboardShortcuts.dispatchKeyEvent(event, this, mUIWithNativeInitialized); + Boolean result = KeyboardShortcuts.dispatchKeyEvent(event, mUIWithNativeInitialized, + getFullscreenManager(), /* menuOrKeyboardActionController= */ this); return result != null ? result : super.dispatchKeyEvent(event); } @@ -2435,7 +2438,8 @@ } boolean isCurrentTabVisible = !mOverviewModeController.overviewVisible() && (!isTablet() || getCurrentTabModel().getCount() != 0); - return KeyboardShortcuts.onKeyDown(event, this, isCurrentTabVisible, true) + return KeyboardShortcuts.onKeyDown(event, isCurrentTabVisible, true, getTabModelSelector(), + /* menuOrKeyboardActionController= */ this, getToolbarManager()) || super.onKeyDown(keyCode, event); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS index 2056347..4f7036b2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -23,9 +23,6 @@ "ChromeTabbedActivity\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], - "KeyboardShortcuts\.java": [ - "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", - ], "LaunchIntentDispatcher\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java index a8759b5..aa2505a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
@@ -13,10 +13,13 @@ import org.chromium.base.annotations.VerifiesOnN; import org.chromium.chrome.R; -import org.chromium.chrome.browser.app.ChromeActivity; +import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; +import org.chromium.chrome.browser.toolbar.ToolbarManager; +import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; import org.chromium.content_public.browser.WebContents; import org.chromium.device.gamepad.GamepadList; @@ -47,14 +50,16 @@ * the key event. So the keys handled here cannot be overridden by any view or web page. * * @param event The KeyEvent to handle. - * @param activity The ChromeActivity in which the key was pressed. * @param uiInitialized Whether the UI has been initialized. If this is false, most keys will * not be handled. + * @param fullscreenManager Manages fullscreen state. + * @param menuOrKeyboardActionController Controls keyboard actions. * @return True if the event was handled. False if the event was ignored. Null if the event * should be handled by the activity's parent class. */ - public static Boolean dispatchKeyEvent(KeyEvent event, ChromeActivity activity, - boolean uiInitialized) { + public static Boolean dispatchKeyEvent(KeyEvent event, boolean uiInitialized, + FullscreenManager fullscreenManager, + MenuOrKeyboardActionController menuOrKeyboardActionController) { int keyCode = event.getKeyCode(); if (!uiInitialized) { if (keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_MENU) return true; @@ -64,19 +69,23 @@ switch (keyCode) { case KeyEvent.KEYCODE_SEARCH: if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.focus_url_bar, false); } // Always consume the SEARCH key events to prevent android from showing // the default app search UI, which locks up Chrome. return true; case KeyEvent.KEYCODE_MENU: if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - activity.onMenuOrKeyboardAction(R.id.show_menu, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.show_menu, false); } return true; case KeyEvent.KEYCODE_ESCAPE: if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { - if (activity.exitFullscreenIfShowing()) return true; + if (fullscreenManager.getPersistentFullscreenMode()) { + fullscreenManager.exitPersistentFullscreenMode(); + return true; + } } break; case KeyEvent.KEYCODE_TV: @@ -186,15 +195,19 @@ * the key event. So the keys handled here *can* be overridden by any view or web page. * * @param event The KeyEvent to handle. - * @param activity The ChromeActivity in which the key was pressed. - * @param isCurrentTabVisible Whether page-related actions are valid, e.g. reload, zoom in. - * This should be false when in the tab switcher. + * @param isCurrentTabVisible Whether page-related actions are valid, e.g. reload, zoom in. This + * should be false when in the tab switcher. * @param tabSwitchingEnabled Whether shortcuts that switch between tabs are enabled (e.g. - * Ctrl+Tab, Ctrl+3). + * Ctrl+Tab, Ctrl+3). + * @param tabModelSelector The current tab modelSelector. + * @param menuOrKeyboardActionController Controls keyboard actions. + * @param toolbarManager Manages the toolbar. * @return Whether the key event was handled. */ - public static boolean onKeyDown(KeyEvent event, ChromeActivity activity, - boolean isCurrentTabVisible, boolean tabSwitchingEnabled) { + public static boolean onKeyDown(KeyEvent event, boolean isCurrentTabVisible, + boolean tabSwitchingEnabled, TabModelSelector tabModelSelector, + MenuOrKeyboardActionController menuOrKeyboardActionController, + ToolbarManager toolbarManager) { int keyCode = event.getKeyCode(); if (event.getRepeatCount() != 0 || KeyEvent.isModifierKey(keyCode)) return false; if (KeyEvent.isGamepadButton(keyCode)) { @@ -207,26 +220,31 @@ return false; } - TabModel curModel = activity.getCurrentTabModel(); - int count = curModel.getCount(); + TabModel currentTabModel = tabModelSelector.getCurrentModel(); + Tab currentTab = tabModelSelector.getCurrentTab(); + WebContents currentWebContents = currentTab == null ? null : currentTab.getWebContents(); + int tabCount = currentTabModel.getCount(); int metaState = getMetaState(event); int keyCodeAndMeta = keyCode | metaState; switch (keyCodeAndMeta) { case CTRL | SHIFT | KeyEvent.KEYCODE_T: - activity.onMenuOrKeyboardAction(R.id.open_recently_closed_tab, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.open_recently_closed_tab, false); return true; case CTRL | KeyEvent.KEYCODE_T: - activity.onMenuOrKeyboardAction(curModel.isIncognito() - ? R.id.new_incognito_tab_menu_id - : R.id.new_tab_menu_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(currentTabModel.isIncognito() + ? R.id.new_incognito_tab_menu_id + : R.id.new_tab_menu_id, + false); return true; case CTRL | KeyEvent.KEYCODE_N: - activity.onMenuOrKeyboardAction(R.id.new_tab_menu_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.new_tab_menu_id, false); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_N: - activity.onMenuOrKeyboardAction(R.id.new_incognito_tab_menu_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.new_incognito_tab_menu_id, false); return true; // Alt+E represents a special character ´ (latin code: ´) in Android. // If an EditText or ContentView has focus, Alt+E will be swallowed by @@ -235,20 +253,20 @@ case ALT | KeyEvent.KEYCODE_F: case KeyEvent.KEYCODE_F10: case KeyEvent.KEYCODE_BUTTON_Y: - activity.onMenuOrKeyboardAction(R.id.show_menu, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.show_menu, false); return true; } if (isCurrentTabVisible) { if (tabSwitchingEnabled && (metaState == CTRL || metaState == ALT)) { int numCode = keyCode - KeyEvent.KEYCODE_0; - if (numCode > 0 && numCode <= Math.min(count, 8)) { + if (numCode > 0 && numCode <= Math.min(tabCount, 8)) { // Ctrl+1 to Ctrl+8: select tab by index - TabModelUtils.setIndex(curModel, numCode - 1); + TabModelUtils.setIndex(currentTabModel, numCode - 1); return true; - } else if (numCode == 9 && count != 0) { + } else if (numCode == 9 && tabCount != 0) { // Ctrl+9: select last tab - TabModelUtils.setIndex(curModel, count - 1); + TabModelUtils.setIndex(currentTabModel, tabCount - 1); return true; } } @@ -257,102 +275,101 @@ case CTRL | KeyEvent.KEYCODE_TAB: case CTRL | KeyEvent.KEYCODE_PAGE_DOWN: case KeyEvent.KEYCODE_BUTTON_R1: - if (tabSwitchingEnabled && count > 1) { - TabModelUtils.setIndex(curModel, (curModel.index() + 1) % count); + if (tabSwitchingEnabled && tabCount > 1) { + TabModelUtils.setIndex( + currentTabModel, (currentTabModel.index() + 1) % tabCount); } return true; case CTRL | SHIFT | KeyEvent.KEYCODE_TAB: case CTRL | KeyEvent.KEYCODE_PAGE_UP: case KeyEvent.KEYCODE_BUTTON_L1: - if (tabSwitchingEnabled && count > 1) { - TabModelUtils.setIndex(curModel, (curModel.index() + count - 1) % count); + if (tabSwitchingEnabled && tabCount > 1) { + TabModelUtils.setIndex(currentTabModel, + (currentTabModel.index() + tabCount - 1) % tabCount); } return true; case CTRL | KeyEvent.KEYCODE_W: case CTRL | KeyEvent.KEYCODE_F4: case KeyEvent.KEYCODE_BUTTON_B: - TabModelUtils.closeCurrentTab(curModel); + TabModelUtils.closeCurrentTab(currentTabModel); return true; case CTRL | KeyEvent.KEYCODE_F: case CTRL | KeyEvent.KEYCODE_G: case CTRL | SHIFT | KeyEvent.KEYCODE_G: case KeyEvent.KEYCODE_F3: case SHIFT | KeyEvent.KEYCODE_F3: - activity.onMenuOrKeyboardAction(R.id.find_in_page_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.find_in_page_id, false); return true; case CTRL | KeyEvent.KEYCODE_L: case ALT | KeyEvent.KEYCODE_D: case KeyEvent.KEYCODE_BUTTON_X: - activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.focus_url_bar, false); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_B: - activity.onMenuOrKeyboardAction(R.id.all_bookmarks_menu_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.all_bookmarks_menu_id, false); return true; case KeyEvent.KEYCODE_BOOKMARK: case CTRL | KeyEvent.KEYCODE_D: - activity.onMenuOrKeyboardAction(R.id.bookmark_this_page_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.bookmark_this_page_id, false); return true; case CTRL | KeyEvent.KEYCODE_H: - activity.onMenuOrKeyboardAction(R.id.open_history_menu_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.open_history_menu_id, false); return true; case CTRL | KeyEvent.KEYCODE_P: - activity.onMenuOrKeyboardAction(R.id.print_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.print_id, false); return true; case CTRL | KeyEvent.KEYCODE_PLUS: case CTRL | KeyEvent.KEYCODE_EQUALS: case CTRL | SHIFT | KeyEvent.KEYCODE_PLUS: case CTRL | SHIFT | KeyEvent.KEYCODE_EQUALS: case KeyEvent.KEYCODE_ZOOM_IN: - ZoomController.zoomIn(getCurrentWebContents(activity)); + ZoomController.zoomIn(currentWebContents); return true; case CTRL | KeyEvent.KEYCODE_MINUS: case KeyEvent.KEYCODE_ZOOM_OUT: - ZoomController.zoomOut(getCurrentWebContents(activity)); + ZoomController.zoomOut(currentWebContents); return true; case CTRL | KeyEvent.KEYCODE_0: - ZoomController.zoomReset(getCurrentWebContents(activity)); + ZoomController.zoomReset(currentWebContents); return true; case SHIFT | CTRL | KeyEvent.KEYCODE_R: case CTRL | KeyEvent.KEYCODE_R: case SHIFT | KeyEvent.KEYCODE_F5: case KeyEvent.KEYCODE_F5: - Tab tab = activity.getActivityTab(); - if (tab != null) { + if (currentTab != null) { if ((keyCodeAndMeta & SHIFT) == SHIFT) { - tab.reloadIgnoringCache(); + currentTab.reloadIgnoringCache(); } else { - tab.reload(); + currentTab.reload(); } - if (activity.getToolbarManager() != null - && tab.getWebContents() != null - && tab.getWebContents().focusLocationBarByDefault()) { - activity.getToolbarManager().revertLocationBarChanges(); - } else { - if (tab.getView() != null) tab.getView().requestFocus(); + if (toolbarManager != null && currentWebContents != null + && currentWebContents.focusLocationBarByDefault()) { + toolbarManager.revertLocationBarChanges(); + } else if (currentTab.getView() != null) { + currentTab.getView().requestFocus(); } } return true; case ALT | KeyEvent.KEYCODE_DPAD_LEFT: - tab = activity.getActivityTab(); - if (tab != null && tab.canGoBack()) tab.goBack(); + if (currentTab != null && currentTab.canGoBack()) currentTab.goBack(); return true; case ALT | KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_FORWARD: case KeyEvent.KEYCODE_BUTTON_START: - tab = activity.getActivityTab(); - if (tab != null && tab.canGoForward()) tab.goForward(); + if (currentTab != null && currentTab.canGoForward()) currentTab.goForward(); return true; case CTRL | SHIFT | KeyEvent.KEYCODE_SLASH: // i.e. Ctrl+? - activity.onMenuOrKeyboardAction(R.id.help_id, false); + menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.help_id, false); return true; } } return false; } - - private static WebContents getCurrentWebContents(ChromeActivity activity) { - return activity.getActivityTab().getWebContents(); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index 467cd4c..508ad95 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -7,6 +7,7 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; +import android.app.Fragment; import android.app.SearchManager; import android.app.assist.AssistContent; import android.content.ActivityNotFoundException; @@ -2507,6 +2508,12 @@ } } + @Override + public void onAttachFragment(Fragment fragment) { + if (mRootUiCoordinator == null) return; + mRootUiCoordinator.onAttachFragment(fragment); + } + private boolean shouldDisableHardwareAcceleration() { // Low end devices should disable hardware acceleration for memory gains. return SysUtils.isLowEndDevice();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java index 5c24525..94d3023 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -104,43 +104,91 @@ void onCouldNotNormalize(AutofillProfile profile); } + @VisibleForTesting + static class ValueWithStatus { + static final ValueWithStatus EMPTY = new ValueWithStatus("", VerificationStatus.NO_STATUS); + + private final String mValue; + private final @VerificationStatus int mStatus; + + ValueWithStatus(String value, @VerificationStatus int status) { + mValue = value; + mStatus = status; + } + + String getValue() { + return mValue; + } + + @VerificationStatus + int getStatus() { + return mStatus; + } + } + /** * Autofill address information. + * The creation and/or modification of an AutofillProfile is assumed to involve the user (e.g. + * data reviewed by the user in the {@link + * org.chromium.chrome.browser.autofill.settings.AddressEditor}), therefore all new values gain + * {@link VerificationStatus.USER_VERIFIED} status. */ public static class AutofillProfile { private String mGUID; private String mOrigin; private boolean mIsLocal; - private String mHonorificPrefix; - private String mFullName; - private String mCompanyName; - private String mStreetAddress; - private String mRegion; - private String mLocality; - private String mDependentLocality; - private String mPostalCode; - private String mSortingCode; - private String mCountryCode; - private String mPhoneNumber; - private String mEmailAddress; + private ValueWithStatus mHonorificPrefix; + private ValueWithStatus mFullName; + private ValueWithStatus mCompanyName; + private ValueWithStatus mStreetAddress; + private ValueWithStatus mRegion; + private ValueWithStatus mLocality; + private ValueWithStatus mDependentLocality; + private ValueWithStatus mPostalCode; + private ValueWithStatus mSortingCode; + private ValueWithStatus mCountryCode; + private ValueWithStatus mPhoneNumber; + private ValueWithStatus mEmailAddress; private String mLabel; private String mLanguageCode; @CalledByNative("AutofillProfile") - public static AutofillProfile create(String guid, String origin, boolean isLocal, - String honorificPrefix, String fullName, String companyName, String streetAddress, - String region, String locality, String dependentLocality, String postalCode, - String sortingCode, String country, String phoneNumber, String emailAddress, - String languageCode) { - return new AutofillProfile(guid, origin, isLocal, honorificPrefix, fullName, - companyName, streetAddress, region, locality, dependentLocality, postalCode, - sortingCode, country, phoneNumber, emailAddress, languageCode); + private static AutofillProfile create(String guid, String origin, boolean isLocal, + String honorificPrefix, @VerificationStatus int honorificPrefixStatus, + String fullName, @VerificationStatus int fullNameStatus, String companyName, + @VerificationStatus int companyNameStatus, String streetAddress, + @VerificationStatus int streetAddressStatus, String region, + @VerificationStatus int regionStatus, String locality, + @VerificationStatus int localityStatus, String dependentLocality, + @VerificationStatus int dependentLocalityStatus, String postalCode, + @VerificationStatus int postalCodeStatus, String sortingCode, + @VerificationStatus int sortingCodeStatus, String countryCode, + @VerificationStatus int countryCodeStatus, String phoneNumber, + @VerificationStatus int phoneNumberStatus, String emailAddress, + @VerificationStatus int emailAddressStatus, String languageCode) { + return new AutofillProfile(guid, origin, isLocal, + new ValueWithStatus(honorificPrefix, honorificPrefixStatus), + new ValueWithStatus(fullName, fullNameStatus), + new ValueWithStatus(companyName, companyNameStatus), + new ValueWithStatus(streetAddress, streetAddressStatus), + new ValueWithStatus(region, regionStatus), + new ValueWithStatus(locality, localityStatus), + new ValueWithStatus(dependentLocality, dependentLocalityStatus), + new ValueWithStatus(postalCode, postalCodeStatus), + new ValueWithStatus(sortingCode, sortingCodeStatus), + new ValueWithStatus(countryCode, countryCodeStatus), + new ValueWithStatus(phoneNumber, phoneNumberStatus), + new ValueWithStatus(emailAddress, emailAddressStatus), languageCode); } - public AutofillProfile(String guid, String origin, boolean isLocal, String honorificPrefix, - String fullName, String companyName, String streetAddress, String region, - String locality, String dependentLocality, String postalCode, String sortingCode, - String countryCode, String phoneNumber, String emailAddress, String languageCode) { + @VisibleForTesting + AutofillProfile(String guid, String origin, boolean isLocal, + ValueWithStatus honorificPrefix, ValueWithStatus fullName, + ValueWithStatus companyName, ValueWithStatus streetAddress, ValueWithStatus region, + ValueWithStatus locality, ValueWithStatus dependentLocality, + ValueWithStatus postalCode, ValueWithStatus sortingCode, + ValueWithStatus countryCode, ValueWithStatus phoneNumber, + ValueWithStatus emailAddress, String languageCode) { mGUID = guid; mOrigin = origin; mIsLocal = isLocal; @@ -160,16 +208,46 @@ } /** + * Builds a profile with the given values, assuming those are reviewed by the user and thus + * are marked {@link VerificationStatus.USER_VERIFIED}. + */ + public AutofillProfile(String guid, String origin, boolean isLocal, String honorificPrefix, + String fullName, String companyName, String streetAddress, String region, + String locality, String dependentLocality, String postalCode, String sortingCode, + String countryCode, String phoneNumber, String emailAddress, String languageCode) { + this(guid, origin, isLocal, + new ValueWithStatus(honorificPrefix, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(fullName, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(companyName, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(streetAddress, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(region, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(locality, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(dependentLocality, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(postalCode, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(sortingCode, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(countryCode, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(phoneNumber, VerificationStatus.USER_VERIFIED), + new ValueWithStatus(emailAddress, VerificationStatus.USER_VERIFIED), + languageCode); + } + + /** * Builds an empty local profile with "settings" origin and country code from the default - * locale. All other fields are empty strings, because JNI does not handle null strings. + * locale. All other fields are empty strings with {@link VerificationStatus.NO_STATUS}, + * because JNI does not handle null strings. */ public AutofillProfile() { this("" /* guid */, AutofillEditorBase.SETTINGS_ORIGIN /* origin */, true /* isLocal */, - "" /* honorificPrefix */, "" /* fullName */, "" /* companyName */, - "" /* streetAddress */, "" /* region */, "" /* locality */, - "" /* dependentLocality */, "" /* postalCode */, "" /* sortingCode */, - Locale.getDefault().getCountry() /* country */, "" /* phoneNumber */, - "" /* emailAddress */, "" /* languageCode */); + ValueWithStatus.EMPTY /* honorificPrefix */, + ValueWithStatus.EMPTY /* fullName */, ValueWithStatus.EMPTY /* companyName */, + ValueWithStatus.EMPTY /* streetAddress */, ValueWithStatus.EMPTY /* region */, + ValueWithStatus.EMPTY /* locality */, + ValueWithStatus.EMPTY /* dependentLocality */, + ValueWithStatus.EMPTY /* postalCode */, ValueWithStatus.EMPTY /* sortingCode */, + new ValueWithStatus(Locale.getDefault().getCountry(), + VerificationStatus.USER_VERIFIED) /* country */, + ValueWithStatus.EMPTY /* phoneNumber */, + ValueWithStatus.EMPTY /* emailAddress */, "" /* languageCode */); } /* Builds an AutofillProfile that is an exact copy of the one passed as parameter. */ @@ -177,18 +255,27 @@ mGUID = profile.getGUID(); mOrigin = profile.getOrigin(); mIsLocal = profile.getIsLocal(); - mHonorificPrefix = profile.getHonorificPrefix(); - mFullName = profile.getFullName(); - mCompanyName = profile.getCompanyName(); - mStreetAddress = profile.getStreetAddress(); - mRegion = profile.getRegion(); - mLocality = profile.getLocality(); - mDependentLocality = profile.getDependentLocality(); - mPostalCode = profile.getPostalCode(); - mSortingCode = profile.getSortingCode(); - mCountryCode = profile.getCountryCode(); - mPhoneNumber = profile.getPhoneNumber(); - mEmailAddress = profile.getEmailAddress(); + mHonorificPrefix = new ValueWithStatus( + profile.getHonorificPrefix(), profile.getHonorificPrefixStatus()); + mFullName = new ValueWithStatus(profile.getFullName(), profile.getFullNameStatus()); + mCompanyName = + new ValueWithStatus(profile.getCompanyName(), profile.getCompanyNameStatus()); + mStreetAddress = new ValueWithStatus( + profile.getStreetAddress(), profile.getStreetAddressStatus()); + mRegion = new ValueWithStatus(profile.getRegion(), profile.getRegionStatus()); + mLocality = new ValueWithStatus(profile.getLocality(), profile.getLocalityStatus()); + mDependentLocality = new ValueWithStatus( + profile.getDependentLocality(), profile.getDependentLocalityStatus()); + mPostalCode = + new ValueWithStatus(profile.getPostalCode(), profile.getPostalCodeStatus()); + mSortingCode = + new ValueWithStatus(profile.getSortingCode(), profile.getSortingCodeStatus()); + mCountryCode = + new ValueWithStatus(profile.getCountryCode(), profile.getCountryCodeStatus()); + mPhoneNumber = + new ValueWithStatus(profile.getPhoneNumber(), profile.getPhoneNumberStatus()); + mEmailAddress = + new ValueWithStatus(profile.getEmailAddress(), profile.getEmailAddressStatus()); mLanguageCode = profile.getLanguageCode(); mLabel = profile.getLabel(); } @@ -216,37 +303,81 @@ @CalledByNative("AutofillProfile") public String getHonorificPrefix() { - return mHonorificPrefix; + return mHonorificPrefix.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getHonorificPrefixStatus() { + return mHonorificPrefix.getStatus(); } @CalledByNative("AutofillProfile") public String getFullName() { - return mFullName; + return mFullName.getValue(); + } + + @CalledByNative("AutofillProfile") + @VisibleForTesting + @VerificationStatus + int getFullNameStatus() { + return mFullName.getStatus(); } @CalledByNative("AutofillProfile") public String getCompanyName() { - return mCompanyName; + return mCompanyName.getValue(); + } + + @CalledByNative("AutofillProfile") + @VerificationStatus + int getCompanyNameStatus() { + return mCompanyName.getStatus(); } @CalledByNative("AutofillProfile") public String getStreetAddress() { - return mStreetAddress; + return mStreetAddress.getValue(); + } + + @CalledByNative("AutofillProfile") + @VisibleForTesting + @VerificationStatus + int getStreetAddressStatus() { + return mStreetAddress.getStatus(); } @CalledByNative("AutofillProfile") public String getRegion() { - return mRegion; + return mRegion.getValue(); + } + + @CalledByNative("AutofillProfile") + @VisibleForTesting + @VerificationStatus + int getRegionStatus() { + return mRegion.getStatus(); } @CalledByNative("AutofillProfile") public String getLocality() { - return mLocality; + return mLocality.getValue(); + } + + @CalledByNative("AutofillProfile") + @VisibleForTesting + @VerificationStatus + int getLocalityStatus() { + return mLocality.getStatus(); } @CalledByNative("AutofillProfile") public String getDependentLocality() { - return mDependentLocality; + return mDependentLocality.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getDependentLocalityStatus() { + return mDependentLocality.getStatus(); } public String getLabel() { @@ -255,27 +386,54 @@ @CalledByNative("AutofillProfile") public String getPostalCode() { - return mPostalCode; + return mPostalCode.getValue(); + } + + @CalledByNative("AutofillProfile") + @VisibleForTesting + @VerificationStatus + int getPostalCodeStatus() { + return mPostalCode.getStatus(); } @CalledByNative("AutofillProfile") public String getSortingCode() { - return mSortingCode; + return mSortingCode.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getSortingCodeStatus() { + return mSortingCode.getStatus(); } @CalledByNative("AutofillProfile") public String getCountryCode() { - return mCountryCode; + return mCountryCode.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getCountryCodeStatus() { + return mCountryCode.getStatus(); } @CalledByNative("AutofillProfile") public String getPhoneNumber() { - return mPhoneNumber; + return mPhoneNumber.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getPhoneNumberStatus() { + return mPhoneNumber.getStatus(); } @CalledByNative("AutofillProfile") public String getEmailAddress() { - return mEmailAddress; + return mEmailAddress.getValue(); + } + + @CalledByNative("AutofillProfile") + private @VerificationStatus int getEmailAddressStatus() { + return mEmailAddress.getStatus(); } @CalledByNative("AutofillProfile") @@ -300,51 +458,53 @@ } public void setHonorificPrefix(String honorificPrefix) { - mHonorificPrefix = honorificPrefix; + mHonorificPrefix = + new ValueWithStatus(honorificPrefix, VerificationStatus.USER_VERIFIED); } public void setFullName(String fullName) { - mFullName = fullName; + mFullName = new ValueWithStatus(fullName, VerificationStatus.USER_VERIFIED); } public void setCompanyName(String companyName) { - mCompanyName = companyName; + mCompanyName = new ValueWithStatus(companyName, VerificationStatus.USER_VERIFIED); } public void setStreetAddress(String streetAddress) { - mStreetAddress = streetAddress; + mStreetAddress = new ValueWithStatus(streetAddress, VerificationStatus.USER_VERIFIED); } public void setRegion(String region) { - mRegion = region; + mRegion = new ValueWithStatus(region, VerificationStatus.USER_VERIFIED); } public void setLocality(String locality) { - mLocality = locality; + mLocality = new ValueWithStatus(locality, VerificationStatus.USER_VERIFIED); } public void setDependentLocality(String dependentLocality) { - mDependentLocality = dependentLocality; + mDependentLocality = + new ValueWithStatus(dependentLocality, VerificationStatus.USER_VERIFIED); } public void setPostalCode(String postalCode) { - mPostalCode = postalCode; + mPostalCode = new ValueWithStatus(postalCode, VerificationStatus.USER_VERIFIED); } public void setSortingCode(String sortingCode) { - mSortingCode = sortingCode; + mSortingCode = new ValueWithStatus(sortingCode, VerificationStatus.USER_VERIFIED); } public void setCountryCode(String countryCode) { - mCountryCode = countryCode; + mCountryCode = new ValueWithStatus(countryCode, VerificationStatus.USER_VERIFIED); } public void setPhoneNumber(String phoneNumber) { - mPhoneNumber = phoneNumber; + mPhoneNumber = new ValueWithStatus(phoneNumber, VerificationStatus.USER_VERIFIED); } public void setEmailAddress(String emailAddress) { - mEmailAddress = emailAddress; + mEmailAddress = new ValueWithStatus(emailAddress, VerificationStatus.USER_VERIFIED); } public void setLanguageCode(String languageCode) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java index 3839a19..f039106 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -26,7 +26,6 @@ import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.fullscreen.FullscreenManager; -import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.components.VirtualView; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; @@ -86,7 +85,6 @@ * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}. * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}. - * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. */ public LayoutManagerChrome(LayoutManagerHost host, ViewGroup contentContainer, @@ -94,10 +92,9 @@ ObservableSupplier<TabContentManager> tabContentManagerSupplier, Supplier<LayerTitleCache> layerTitleCacheSupplier, OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier, - OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier, Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { super(host, contentContainer, tabContentManagerSupplier, layerTitleCacheSupplier, - layoutStateProviderOneshotSupplier, topUiThemeColorProvider); + topUiThemeColorProvider); Context context = host.getContext(); LayoutRenderHost renderHost = host.getLayoutRenderHost();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java index 866caea4..2b8bbe48 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -14,7 +14,6 @@ import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.phone.SimpleAnimationLayout; import org.chromium.chrome.browser.device.DeviceClassManager; -import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; @@ -42,7 +41,6 @@ * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}. * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}. - * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. */ public LayoutManagerChromePhone(LayoutManagerHost host, ViewGroup contentContainer, @@ -50,11 +48,9 @@ ObservableSupplier<TabContentManager> tabContentManagerSupplier, Supplier<LayerTitleCache> layerTitleCacheSupplier, OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier, - OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier, Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { super(host, contentContainer, true, startSurface, tabContentManagerSupplier, - layerTitleCacheSupplier, overviewModeBehaviorSupplier, - layoutStateProviderOneshotSupplier, topUiThemeColorProvider); + layerTitleCacheSupplier, overviewModeBehaviorSupplier, topUiThemeColorProvider); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java index 80fc087..556b5bc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -13,7 +13,6 @@ import org.chromium.chrome.browser.compositor.LayerTitleCache; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager; -import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; @@ -40,18 +39,15 @@ * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param layerTitleCacheSupplier Supplier of the {@link LayerTitleCache}. * @param overviewModeBehaviorSupplier Supplier of the {@link OverviewModeBehavior}. - * @param layoutStateProviderOneshotSupplier Supplier of the {@link LayoutStateProvider}. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. */ public LayoutManagerChromeTablet(LayoutManagerHost host, ViewGroup contentContainer, ObservableSupplier<TabContentManager> tabContentManagerSupplier, Supplier<LayerTitleCache> layerTitleCacheSupplier, OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier, - OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier, Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { super(host, contentContainer, false, null, tabContentManagerSupplier, - layerTitleCacheSupplier, overviewModeBehaviorSupplier, - layoutStateProviderOneshotSupplier, topUiThemeColorProvider); + layerTitleCacheSupplier, overviewModeBehaviorSupplier, topUiThemeColorProvider); mTabStripLayoutHelperManager = new StripLayoutHelperManager(host.getContext(), this, mHost.getLayoutRenderHost(), () -> mTitleCache, layerTitleCacheSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java index e6ed389e..7d9184c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
@@ -20,7 +20,6 @@ import org.chromium.base.TraceEvent; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; -import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils; @@ -37,7 +36,6 @@ import org.chromium.chrome.browser.gesturenav.HistoryNavigationCoordinator; import org.chromium.chrome.browser.layouts.CompositorModelChangeProcessor; import org.chromium.chrome.browser.layouts.EventFilter; -import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.layouts.ManagedLayoutManager; import org.chromium.chrome.browser.layouts.SceneOverlay; @@ -169,9 +167,6 @@ /** A map of {@link SceneOverlay} to its position relative to the others. */ private Map<Class, Integer> mOverlayOrderMap = new HashMap<>(); - /** The supplier used to supply the LayoutStateProvider. */ - private final OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderOneshotSupplier; - /** The supplier of {@link ThemeColorProvider} for top UI. */ private final Supplier<TopUiThemeColorProvider> mTopUiThemeColorProvider; @@ -256,19 +251,15 @@ * @param contentContainer A {@link ViewGroup} for Android views to be bound to. * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance. * @param layerTitleCacheSupplier A supplier of the cache of title textures. - * @param layoutStateProviderOneshotSupplier Supplier used to supply the {@link - * LayoutStateProvider}. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. */ public LayoutManagerImpl(LayoutManagerHost host, ViewGroup contentContainer, ObservableSupplier<TabContentManager> tabContentManagerSupplier, Supplier<LayerTitleCache> layerTitleCacheSupplier, - OneshotSupplierImpl<LayoutStateProvider> layoutStateProviderOneshotSupplier, Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { mHost = host; mPxToDp = 1.f / mHost.getContext().getResources().getDisplayMetrics().density; mTabContentManagerSupplier = tabContentManagerSupplier; - mLayoutStateProviderOneshotSupplier = layoutStateProviderOneshotSupplier; mLayerTitleCacheSupplier = layerTitleCacheSupplier; mTopUiThemeColorProvider = topUiThemeColorProvider; mContext = host.getContext(); @@ -297,8 +288,6 @@ mFrameRequestSupplier = new CompositorModelChangeProcessor.FrameRequestSupplier(this::requestUpdate); - - mLayoutStateProviderOneshotSupplier.set(this); } /** @@ -904,18 +893,22 @@ public void startHiding(int nextTabId, boolean hintAtTabSelection) { requestUpdate(); if (hintAtTabSelection) { - notifyObserversOnTabSelectionHinted(nextTabId); - // TODO(crbug.com/1108496): Remove after migrates to LayoutStateObserver. for (SceneChangeObserver observer : mSceneChangeObservers) { observer.onTabSelectionHinted(nextTabId); } + + for (LayoutStateObserver observer : mLayoutObservers) { + observer.onTabSelectionHinted(nextTabId); + } } Layout layoutBeingHidden = getActiveLayout(); - notifyObserversLayoutStartedHiding(layoutBeingHidden.getLayoutType(), - shouldShowToolbarAnimationOnHide(layoutBeingHidden, nextTabId), - shouldDelayHideAnimation(layoutBeingHidden)); + for (LayoutStateObserver observer : mLayoutObservers) { + observer.onStartedHiding(layoutBeingHidden.getLayoutType(), + shouldShowToolbarAnimationOnHide(layoutBeingHidden, nextTabId), + shouldDelayHideAnimation(layoutBeingHidden)); + } } @Override @@ -925,7 +918,9 @@ assert mNextActiveLayout != null : "Need to have a next active layout."; if (mNextActiveLayout != null) { // Notify LayoutObservers the active layout is finished hiding. - notifyObserversLayoutFinishedHiding(getActiveLayout().getLayoutType()); + for (LayoutStateObserver observer : mLayoutObservers) { + observer.onFinishedHiding(getActiveLayout().getLayoutType()); + } startShowing(mNextActiveLayout, true); } @@ -934,7 +929,9 @@ @Override public void doneShowing() { // Notify LayoutObservers the active layout is finished showing. - notifyObserversLayoutFinishedShowing(getActiveLayout().getLayoutType()); + for (LayoutStateObserver observer : mLayoutObservers) { + observer.onFinishedShowing(getActiveLayout().getLayoutType()); + } } /** @@ -993,8 +990,10 @@ observer.onSceneChange(getActiveLayout()); } - notifyObserversLayoutStartedShowing( - layout.getLayoutType(), shouldShowToolbarAnimationOnShow(animate)); + for (LayoutStateObserver observer : mLayoutObservers) { + observer.onStartedShowing( + layout.getLayoutType(), shouldShowToolbarAnimationOnShow(animate)); + } } /** @@ -1011,6 +1010,11 @@ return layout == mActiveLayout; } + @Override + public int getActiveLayoutType() { + return getActiveLayout() != null ? getActiveLayout().getLayoutType() : LayoutType.NONE; + } + /** * Get a list of virtual views for accessibility. * @@ -1124,48 +1128,6 @@ mLayoutObservers.removeObserver(listener); } - protected final void notifyObserversLayoutStartedShowing( - @LayoutType int layoutType, boolean showToolbar) { - mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> { - for (LayoutStateObserver observer : mLayoutObservers) { - observer.onStartedShowing(layoutType, showToolbar); - } - }); - } - - protected final void notifyObserversLayoutFinishedShowing(@LayoutType int layoutType) { - mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> { - for (LayoutStateObserver observer : mLayoutObservers) { - observer.onFinishedShowing(layoutType); - } - }); - } - - protected final void notifyObserversLayoutStartedHiding( - @LayoutType int layoutType, boolean showToolbar, boolean delayAnimation) { - mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> { - for (LayoutStateObserver observer : mLayoutObservers) { - observer.onStartedHiding(layoutType, showToolbar, delayAnimation); - } - }); - } - - protected final void notifyObserversLayoutFinishedHiding(@LayoutType int layoutType) { - mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> { - for (LayoutStateObserver observer : mLayoutObservers) { - observer.onFinishedHiding(layoutType); - } - }); - } - - protected final void notifyObserversOnTabSelectionHinted(int tabId) { - mLayoutStateProviderOneshotSupplier.onAvailable((unused) -> { - for (LayoutStateObserver observer : mLayoutObservers) { - observer.onTabSelectionHinted(tabId); - } - }); - } - protected boolean shouldShowToolbarAnimationOnShow(boolean isAnimate) { return false; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index 7cfc41c..79cf4e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -466,8 +466,9 @@ @Override public boolean dispatchKeyEvent(KeyEvent event) { - Boolean result = KeyboardShortcuts.dispatchKeyEvent( - event, this, mToolbarCoordinator.toolbarIsInitialized()); + Boolean result = KeyboardShortcuts.dispatchKeyEvent(event, + mToolbarCoordinator.toolbarIsInitialized(), getFullscreenManager(), + /* menuOrKeyboardActionController= */ this); return result != null ? result : super.dispatchKeyEvent(event); } @@ -494,7 +495,8 @@ if (!mToolbarCoordinator.toolbarIsInitialized()) { return super.onKeyDown(keyCode, event); } - return KeyboardShortcuts.onKeyDown(event, this, true, false) + return KeyboardShortcuts.onKeyDown(event, true, false, getTabModelSelector(), + /* menuOrKeyboardActionController= */ this, getToolbarManager()) || super.onKeyDown(keyCode, event); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java index 174a8267..abc768b4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabCompositorContentInitializer.java
@@ -9,7 +9,6 @@ import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; -import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; @@ -79,7 +78,7 @@ if (mCompositorViewHolder.get() == null) return null; return mCompositorViewHolder.get().getLayerTitleCache(); }, - new OneshotSupplierImpl<>(), () -> mTopUiThemeColorProvider); + () -> mTopUiThemeColorProvider); // clang-format on mCompositorViewHolderInitializer.initializeCompositorContent(layoutDriver,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java index c3a7096..1a812c6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
@@ -9,6 +9,8 @@ import android.content.pm.PackageManager; import android.util.Pair; +import androidx.annotation.NonNull; + import org.chromium.base.ApplicationStatus; import org.chromium.base.Callback; import org.chromium.base.ContextUtils; @@ -158,11 +160,10 @@ /** * Requests the stoarge permission from Java. * @param delegate The permission delegate to be used for file access request. - * TODO(crbug/1209228): Make the delegate non-null. * @param callback Callback to notify if the permission is granted or not. */ public static void requestFileAccessPermission( - AndroidPermissionDelegate delegate, final Callback<Boolean> callback) { + @NonNull AndroidPermissionDelegate delegate, final Callback<Boolean> callback) { requestFileAccessPermissionHelper(delegate, result -> { boolean granted = result.first; String permissions = result.second;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java index 4ca26a1..0439b0c4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java
@@ -194,11 +194,13 @@ mDisplayListener = new DisplayListener() { @Override public void onDisplayAdded(int displayId) { + if (!isNormalDisplay(displayId)) return; sActivityTypePendingMergeOnStartup = null; } @Override public void onDisplayRemoved(int displayId) { + if (!isNormalDisplay(displayId)) return; if (displayId == mDisplayId) { // If activity on removed display is in the foreground, do tab merge. // Note that activity on removed display may be recreated because of the @@ -221,7 +223,7 @@ @Override public void onDisplayChanged(int displayId) { - if (displayId == mDisplayId) return; + if (displayId == mDisplayId || !isNormalDisplay(displayId)) return; List<Integer> ids = sTestDisplayIds != null ? sTestDisplayIds : ApiCompatibilityUtils.getTargetableDisplayIds(mActivity); @@ -233,6 +235,30 @@ displayManager.registerDisplayListener(mDisplayListener, null); } + /** + * Check if the given display is what Chrome can use for showing activity/tab. + * It should be either the default display, or secondary one such as external, + * wireless display. + * @param id ID of the display. + * @return {@code true} if the display is a normal one. + */ + private boolean isNormalDisplay(int id) { + if (id == Display.DEFAULT_DISPLAY || sTestDisplayIds != null) return true; + Display display = getDisplayFromId(id); + return (display != null && (display.getFlags() & Display.FLAG_PRESENTATION) != 0); + } + + private @Nullable Display getDisplayFromId(int id) { + DisplayManager displayManager = + (DisplayManager) mActivity.getSystemService(Context.DISPLAY_SERVICE); + if (displayManager == null) return null; + Display[] displays = displayManager.getDisplays(); + for (Display display : displays) { + if (display.getDisplayId() == id) return display; + } + return null; + } + @Override public void onResumeWithNative() { if (isTabModelMergingEnabled()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java index f61b4dbb..5d6f975 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -50,6 +50,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.toolbar.VoiceToolbarButtonController; import org.chromium.chrome.browser.ui.native_page.NativePage; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.chrome.browser.util.KeyNavigationUtil; @@ -657,6 +658,11 @@ mShouldShowLensButtonWhenUnfocused = shouldShow; } + /* package */ void setShouldShowMicButtonWhenUnfocusedForTesting(boolean shouldShow) { + assert mIsTablet; + mShouldShowMicButtonWhenUnfocused = shouldShow; + } + /** * @param shouldShow Whether buttons should be displayed in the URL bar when it's not * focused. @@ -972,12 +978,16 @@ private boolean shouldShowMicButton() { if (mIsTablet && mShouldShowButtonsWhenUnfocused) { return mVoiceRecognitionHandler != null - && mVoiceRecognitionHandler.isVoiceSearchEnabled() && mNativeInitialized + && mVoiceRecognitionHandler.isVoiceSearchEnabled() + && !VoiceToolbarButtonController.isToolbarMicEnabled() && mNativeInitialized && (mUrlHasFocus || mIsUrlFocusChangeInProgress); } else { boolean deleteButtonVisible = shouldShowDeleteButton(); + boolean canShowMicButton = + !mIsTablet || !VoiceToolbarButtonController.isToolbarMicEnabled(); return mVoiceRecognitionHandler != null - && mVoiceRecognitionHandler.isVoiceSearchEnabled() && !deleteButtonVisible + && mVoiceRecognitionHandler.isVoiceSearchEnabled() && canShowMicButton + && !deleteButtonVisible && (mUrlHasFocus || mIsUrlFocusChangeInProgress || mUrlFocusChangeFraction > 0f || mShouldShowMicButtonWhenUnfocused); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java index d28c2af5..d36a507 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -53,12 +53,15 @@ */ public class ChromeSurveyController implements InfoBarAnimationListener { private static final String TAG = "ChromeSurveyCtrler"; + private static final int DOWNLOAD_ATTEMPTS_HIST_NUM_BUCKETS = 20; @VisibleForTesting static final long REQUIRED_VISIBILITY_DURATION_MS = 5000; @VisibleForTesting public static final String COMMAND_LINE_PARAM_NAME = "survey_override_site_id"; @VisibleForTesting + static final String MAX_DOWNLOAD_ATTEMPTS = "max-download-attempts"; + @VisibleForTesting static final String MAX_NUMBER = "max-number"; @VisibleForTesting static final String SITE_ID_PARAM_NAME = "site-id"; @@ -110,6 +113,7 @@ private final String mTriggerId; private final String mPrefKeyPromptDisplayed; + private final String mPrefKeyDownloadAttempts; private final @Nullable ActivityLifecycleDispatcher mLifecycleDispatcher; @VisibleForTesting @@ -118,6 +122,8 @@ mTriggerId = triggerId; mPrefKeyPromptDisplayed = ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey(mTriggerId); + mPrefKeyDownloadAttempts = + ChromePreferenceKeys.CHROME_SURVEY_DOWNLOAD_ATTEMPTS.createKey(mTriggerId); mLifecycleDispatcher = lifecycleDispatcher; } @@ -263,6 +269,19 @@ return false; } + private void recordDownloadAttempted() { + SharedPreferencesManager.getInstance().incrementInt(mPrefKeyDownloadAttempts); + } + + /** Return whether the number of download attempts falls within the max cap. */ + private boolean isDownloadAttemptAllowed() { + int maxDownloadAttempts = ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.CHROME_SURVEY_NEXT_ANDROID, MAX_DOWNLOAD_ATTEMPTS, 0); + int downloadAttemptsMade = + SharedPreferencesManager.getInstance().readInt(mPrefKeyDownloadAttempts, 0); + return maxDownloadAttempts <= 0 || downloadAttemptsMade < maxDownloadAttempts; + } + /** * Checks if the tab is valid for a survey (i.e. not null, no null webcontents & not incognito). * @param tab The tab to be checked. @@ -386,6 +405,7 @@ public void onSurveyTriggered() { recordInfoBarClosingState(InfoBarClosingState.ACCEPTED_SURVEY); recordInfoBarDisplayed(); + recordSurveyAccepted(); } @Override @@ -433,6 +453,14 @@ "Android.Survey.InfoBarClosingState", value, InfoBarClosingState.NUM_ENTRIES); } + private void recordSurveyAccepted() { + int downloadAttemptsMade = + SharedPreferencesManager.getInstance().readInt(mPrefKeyDownloadAttempts, 0); + RecordHistogram.recordLinearCountHistogram("Android.Survey.DownloadAttemptsBeforeAccepted", + downloadAttemptsMade, 1, DOWNLOAD_ATTEMPTS_HIST_NUM_BUCKETS, + DOWNLOAD_ATTEMPTS_HIST_NUM_BUCKETS + 1); + } + static class StartDownloadIfEligibleTask extends AsyncTask<Boolean> { ChromeSurveyController mController; final TabModelSelector mSelector; @@ -452,13 +480,16 @@ FilteringResult.FORCE_SURVEY_ON_COMMAND_PRESENT); return true; } - return !mController.hasInfoBarBeenDisplayed() + return !mController.hasInfoBarBeenDisplayed() && mController.isDownloadAttemptAllowed() && mController.isRandomlySelectedForSurvey(); } @Override protected void onPostExecute(Boolean result) { - if (result) mController.startDownload(ContextUtils.getApplicationContext(), mSelector); + if (result) { + mController.startDownload(ContextUtils.getApplicationContext(), mSelector); + mController.recordDownloadAttempted(); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 7156ecc..82aa59a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -812,16 +812,7 @@ mLayoutStateObserver = new LayoutStateProvider.LayoutStateObserver() { @Override public void onStartedShowing(@LayoutType int layoutType, boolean showToolbar) { - if (layoutType == LayoutType.TAB_SWITCHER) { - mLocationBarModel.setIsShowingTabSwitcher(true); - mToolbar.setTabSwitcherMode(true, showToolbar, false); - updateButtonStatus(); - if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) { - assert mLocationBar instanceof LocationBarCoordinator; - ((LocationBarCoordinator) mLocationBar).startAutocompletePrefetch(); - } - } - mToolbar.setContentAttached(layoutType == LayoutType.BROWSING); + updateForLayout(layoutType, showToolbar, false); } @Override @@ -895,6 +886,28 @@ } /** + * Handle a layout change event. + * @param layoutType The layout being switched to. + * @param showToolbar Whether the toolbar should be shown. + * @param shouldFocusOmnibox Whether we should attempt to focus the omnibox. + */ + private void updateForLayout( + @LayoutType int layoutType, boolean showToolbar, boolean shouldFocusOmnibox) { + if (layoutType == LayoutType.TAB_SWITCHER) { + mLocationBarModel.setIsShowingTabSwitcher(true); + mToolbar.setTabSwitcherMode(true, showToolbar, false); + updateButtonStatus(); + if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) { + assert mLocationBar instanceof LocationBarCoordinator; + ((LocationBarCoordinator) mLocationBar).startAutocompletePrefetch(); + } + } + mToolbar.setContentAttached(layoutType == LayoutType.BROWSING); + + if (shouldFocusOmnibox) maybeFocusOmnibox(layoutType, mActivityTabProvider.get()); + } + + /** * May set Omnibox focused if the Tab has the flag to require focusing the Omnibox. */ private void maybeFocusOmnibox(@LayoutType int layout, Tab tab) { @@ -1767,6 +1780,15 @@ mLayoutStateProvider = layoutStateProvider; mLayoutStateProvider.addObserver(mLayoutStateObserver); + + if (mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER)) { + // TODO(1210431): We shouldn't need to post this. Instead we should wait until the + // dependencies are ready. This logic was introduced to move asynchronous + // observer events from the infra (LayoutManager) into the feature using + // it. + mControlContainer.post(() -> updateForLayout(LayoutType.TAB_SWITCHER, true, true)); + } + mAppThemeColorProvider.setLayoutStateProvider(mLayoutStateProvider); mLocationBarModel.setLayoutStateProvider(mLayoutStateProvider); if (mBottomControlsCoordinatorSupplier.get() != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java index 16779d6..1e16b7b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -29,6 +29,7 @@ import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TAB_SWITCHER_BUTTON_IS_VISIBLE; import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.TRANSLATION_Y; +import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; @@ -337,6 +338,14 @@ } } }; + + if (mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER)) { + new Handler().post(() -> { + mLayoutStateObserver.onStartedShowing(LayoutType.TAB_SWITCHER, true); + mLayoutStateObserver.onFinishedShowing(LayoutType.TAB_SWITCHER); + }); + } + mLayoutStateProvider.addObserver(mLayoutStateObserver); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 6c92d82..a2f6546 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.ui; +import android.app.Fragment; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -67,6 +68,7 @@ import org.chromium.chrome.browser.share.ShareDelegate; import org.chromium.chrome.browser.share.ShareDelegate.ShareOrigin; import org.chromium.chrome.browser.share.ShareUtils; +import org.chromium.chrome.browser.share.qrcode.QrCodeDialog; import org.chromium.chrome.browser.tab.AccessibilityVisibilityHandler; import org.chromium.chrome.browser.tab.AutofillSessionLifetimeController; import org.chromium.chrome.browser.tab.Tab; @@ -295,6 +297,13 @@ return mTopUiThemeColorProvider; } + public void onAttachFragment(Fragment fragment) { + if (fragment instanceof QrCodeDialog) { + QrCodeDialog qrCodeDialog = (QrCodeDialog) fragment; + qrCodeDialog.setAndroidPermissionDelegate(mActivity.getWindowAndroid()); + } + } + @Override public void onDestroy() { // TODO(meiliang): Understand why we need to set most of the class member instances to null
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java index 76e8ebd..a3d3359 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -21,6 +21,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.autofill.PersonalDataManager.ValueWithStatus; import org.chromium.chrome.test.ChromeBrowserTestRule; import java.util.LinkedList; @@ -227,6 +228,55 @@ @Test @SmallTest @Feature({"Autofill"}) + public void testRespectVerificationStatuses() throws TimeoutException { + AutofillProfile profileWithDifferentStatuses = new AutofillProfile("" /* guid */, + "" /* origin */, true, + new ValueWithStatus("" /* honorific prefix */, VerificationStatus.NO_STATUS), + new ValueWithStatus("John Smith", VerificationStatus.PARSED), + new ValueWithStatus("" /* company */, VerificationStatus.NO_STATUS), + new ValueWithStatus("1 Main\nApt A", VerificationStatus.FORMATTED), + new ValueWithStatus("Quebec", VerificationStatus.OBSERVED), + new ValueWithStatus("Montreal", VerificationStatus.USER_VERIFIED), + new ValueWithStatus("" /* dependent locality */, VerificationStatus.NO_STATUS), + new ValueWithStatus("H3B 2Y5", VerificationStatus.SERVER_PARSED), + new ValueWithStatus("" /* sorting code */, VerificationStatus.NO_STATUS), + new ValueWithStatus("Canada", VerificationStatus.USER_VERIFIED), + new ValueWithStatus("" /* phone */, VerificationStatus.NO_STATUS), + new ValueWithStatus("" /* email */, VerificationStatus.NO_STATUS), + "" /* language code */); + String guid = mHelper.setProfile(profileWithDifferentStatuses); + Assert.assertEquals(1, mHelper.getNumberOfProfilesForSettings()); + + AutofillProfile storedProfile = mHelper.getProfile(guid); + // When converted to C++ and back the verification statuses for name and address components + // should be preserved. + Assert.assertEquals(VerificationStatus.PARSED, storedProfile.getFullNameStatus()); + Assert.assertEquals(VerificationStatus.FORMATTED, storedProfile.getStreetAddressStatus()); + Assert.assertEquals(VerificationStatus.OBSERVED, storedProfile.getRegionStatus()); + Assert.assertEquals(VerificationStatus.USER_VERIFIED, storedProfile.getLocalityStatus()); + Assert.assertEquals(VerificationStatus.SERVER_PARSED, storedProfile.getPostalCodeStatus()); + } + + @Test + @SmallTest + @Feature({"Autofill"}) + public void testValuesSetInProfileGainUserVerifiedStatus() { + AutofillProfile profile = new AutofillProfile(); + Assert.assertEquals(VerificationStatus.NO_STATUS, profile.getFullNameStatus()); + Assert.assertEquals(VerificationStatus.NO_STATUS, profile.getStreetAddressStatus()); + Assert.assertEquals(VerificationStatus.NO_STATUS, profile.getLocalityStatus()); + + profile.setFullName("Homer Simpson"); + Assert.assertEquals(VerificationStatus.USER_VERIFIED, profile.getFullNameStatus()); + profile.setStreetAddress("123 Main St."); + Assert.assertEquals(VerificationStatus.USER_VERIFIED, profile.getStreetAddressStatus()); + profile.setLocality("Springfield"); + Assert.assertEquals(VerificationStatus.USER_VERIFIED, profile.getLocalityStatus()); + } + + @Test + @SmallTest + @Feature({"Autofill"}) public void testMultilineStreetAddress() throws TimeoutException { final String streetAddress1 = "Chez Mireille COPEAU Appartment. 2\n" + "Entree A Batiment Jonquille\n"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java index c427b86e..13996b1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -121,8 +121,6 @@ private float mDpToPx; - private OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderSupplier; - class LayoutObserverCallbackHelper extends CallbackHelper { @LayoutType public int layoutType; @@ -213,13 +211,9 @@ OneshotSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier = new OneshotSupplierImpl<>(); - if (mLayoutStateProviderSupplier == null) { - mLayoutStateProviderSupplier = new OneshotSupplierImpl<>(); - } - mManagerPhone = new LayoutManagerChromePhone(layoutManagerHost, container, mStartSurface, tabContentManagerSupplier, null, overviewModeBehaviorSupplier, - mLayoutStateProviderSupplier, () -> mTopUiThemeColorProvider); + () -> mTopUiThemeColorProvider); verify(mStartSurfaceController) .addOverviewModeObserver(mStartSurfaceOverviewModeCaptor.capture()); @@ -472,17 +466,10 @@ performToolbarSideSwipe(ScrollDirection.RIGHT); Assert.assertEquals( LayoutType.TOOLBAR_SWIPE, mManager.getActiveLayout().getLayoutType()); - Assert.assertTrue( - mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.TOOLBAR_SWIPE)); + Assert.assertTrue(mManager.isLayoutVisible(LayoutType.TOOLBAR_SWIPE)); }); - // The |startedShowingCallback| callCount 0 is reserved for the default layout during - // initialization. Because LayoutManager does not explicitly hide the old layout when a new - // layout is forced to show, the callCount for |finishedShowingCallback|, - // |startedHidingCallback|, and |finishedHidingCallback| are still 0. - // TODO(crbug.com/1108496): update the callCount when LayoutManager explicitly hide the old - // layout. - startedShowingCallback.waitForCallback(1); + startedShowingCallback.waitForCallback(0); Assert.assertEquals(LayoutType.TOOLBAR_SWIPE, startedShowingCallback.layoutType); finishedShowingCallback.waitForCallback(0); @@ -491,8 +478,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { finishToolbarSideSwipe(); Assert.assertEquals(LayoutType.BROWSING, mManager.getActiveLayout().getLayoutType()); - Assert.assertTrue( - mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.BROWSING)); + Assert.assertTrue(mManager.isLayoutVisible(LayoutType.BROWSING)); }); startedHidingCallback.waitForCallback(0); @@ -501,7 +487,7 @@ finishedHidingCallback.waitForCallback(0); Assert.assertEquals(LayoutType.TOOLBAR_SWIPE, finishedHidingCallback.layoutType); - startedShowingCallback.waitForCallback(2); + startedShowingCallback.waitForCallback(1); Assert.assertEquals(LayoutType.BROWSING, startedShowingCallback.layoutType); finishedShowingCallback.waitForCallback(1); @@ -529,8 +515,7 @@ "layoutManager is way too long to end motion", simulateTime(mManager, 1000)); Assert.assertEquals( LayoutType.TAB_SWITCHER, mManager.getActiveLayout().getLayoutType()); - Assert.assertTrue( - mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.TAB_SWITCHER)); + Assert.assertTrue(mManager.isLayoutVisible(LayoutType.TAB_SWITCHER)); }); // The |startedShowingCallback| callCount 0 is reserved for the default layout during @@ -550,8 +535,7 @@ Assert.assertTrue( "layoutManager is way too long to end motion", simulateTime(mManager, 1000)); - Assert.assertTrue( - mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.BROWSING)); + Assert.assertTrue(mManager.isLayoutVisible(LayoutType.BROWSING)); }); startedHidingCallback.waitForCallback(0); @@ -589,17 +573,10 @@ Assert.assertThat("Incorrect active LayoutType", mManager.getActiveLayout().getLayoutType(), is(LayoutType.SIMPLE_ANIMATION)); Assert.assertThat("Incorrect active Layout", - mLayoutStateProviderSupplier.get().isLayoutVisible(LayoutType.SIMPLE_ANIMATION), - is(true)); + mManager.isLayoutVisible(LayoutType.SIMPLE_ANIMATION), is(true)); }); - // The |startedShowingCallback| callCount 0 is reserved for the default layout during - // initialization. Because LayoutManager does not explicitly hide the old layout when a new - // layout is forced to show, the callCount for |finishedShowingCallback|, - // |startedHidingCallback|, and |finishedHidingCallback| are still 0. - // TODO(crbug.com/1108496): update the callCount when LayoutManager explicitly hide the old - // layout. - startedShowingCallback.waitForCallback(1); + startedShowingCallback.waitForCallback(0); Assert.assertThat("startedShowingCallback with incorrect LayoutType", startedShowingCallback.layoutType, is(LayoutType.SIMPLE_ANIMATION)); @@ -626,7 +603,7 @@ Assert.assertThat("finishedHidingCallback with incorrectLayoutType", finishedHidingCallback.layoutType, is(LayoutType.SIMPLE_ANIMATION)); - startedShowingCallback.waitForCallback(2); + startedShowingCallback.waitForCallback(1); Assert.assertThat("startedShowingCallback with incorrectLayoutType", startedShowingCallback.layoutType, is(LayoutType.BROWSING)); @@ -641,46 +618,46 @@ LayoutObserverCallbackHelper startedHidingCallback, LayoutObserverCallbackHelper finishedHidingCallback) throws TimeoutException { TestThreadUtils.runOnUiThreadBlocking(() -> { - mLayoutStateProviderSupplier = new OneshotSupplierImpl<>(); + initializeLayoutManagerPhone(2, 0); + mManager.addObserver(new LayoutStateProvider.LayoutStateObserver() { + @Override + public void onStartedShowing(int layoutType, boolean showToolbar) { + Log.d(TAG, "Started to show: " + layoutType); + startedShowingCallback.layoutType = layoutType; + startedShowingCallback.notifyCalled(); + } - mLayoutStateProviderSupplier.onAvailable((layoutStateProvider) -> { - layoutStateProvider.addObserver(new LayoutStateProvider.LayoutStateObserver() { - @Override - public void onStartedShowing(int layoutType, boolean showToolbar) { - Log.d(TAG, "Started to show: " + layoutType); - startedShowingCallback.layoutType = layoutType; - startedShowingCallback.notifyCalled(); - } + @Override + public void onFinishedShowing(int layoutType) { + Log.d(TAG, "finished to show: " + layoutType); + finishedShowingCallback.layoutType = layoutType; + finishedShowingCallback.notifyCalled(); + } - @Override - public void onFinishedShowing(int layoutType) { - Log.d(TAG, "finished to show: " + layoutType); - finishedShowingCallback.layoutType = layoutType; - finishedShowingCallback.notifyCalled(); - } + @Override + public void onStartedHiding( + int layoutType, boolean showToolbar, boolean delayAnimation) { + Log.d(TAG, "Started to hide: " + layoutType); + startedHidingCallback.layoutType = layoutType; + startedHidingCallback.notifyCalled(); + } - @Override - public void onStartedHiding( - int layoutType, boolean showToolbar, boolean delayAnimation) { - Log.d(TAG, "Started to hide: " + layoutType); - startedHidingCallback.layoutType = layoutType; - startedHidingCallback.notifyCalled(); - } - - @Override - public void onFinishedHiding(int layoutType) { - Log.d(TAG, "finished to hide: " + layoutType); - finishedHidingCallback.layoutType = layoutType; - finishedHidingCallback.notifyCalled(); - } - }); + @Override + public void onFinishedHiding(int layoutType) { + Log.d(TAG, "finished to hide: " + layoutType); + finishedHidingCallback.layoutType = layoutType; + finishedHidingCallback.notifyCalled(); + } }); - initializeLayoutManagerPhone(2, 0); Assert.assertEquals(LayoutType.BROWSING, mManager.getActiveLayout().getLayoutType()); }); - startedShowingCallback.waitForCallback(0); + if (mManager.isLayoutVisible(LayoutType.BROWSING)) { + startedShowingCallback.layoutType = LayoutType.BROWSING; + } else { + startedShowingCallback.waitForCallback(0); + } Assert.assertEquals(LayoutType.BROWSING, startedShowingCallback.layoutType); } @@ -692,19 +669,15 @@ CallbackHelper tabSelectionHintedCallback = new CallbackHelper(); TestThreadUtils.runOnUiThreadBlocking(() -> { - mLayoutStateProviderSupplier = new OneshotSupplierImpl<>(); - - mLayoutStateProviderSupplier.onAvailable((layoutStateProvider) -> { - layoutStateProvider.addObserver(new LayoutStateProvider.LayoutStateObserver() { - @Override - public void onTabSelectionHinted(int tabId) { - Log.d(TAG, "onTabSelectionHinted"); - tabSelectionHintedCallback.notifyCalled(); - } - }); + initializeLayoutManagerPhone(2, 0); + mManager.addObserver(new LayoutStateProvider.LayoutStateObserver() { + @Override + public void onTabSelectionHinted(int tabId) { + Log.d(TAG, "onTabSelectionHinted"); + tabSelectionHintedCallback.notifyCalled(); + } }); - initializeLayoutManagerPhone(2, 0); mManager.showOverview(true); Assert.assertTrue(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java index 054ce6468..0654131 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
@@ -297,7 +297,7 @@ mActivityTestRule.getActivity().getLayoutManager().hideOverview(false); } }); - LayoutTestUtils.waitForLayout( - mActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER); + LayoutTestUtils.waitForLayout(mActivityTestRule.getActivity().getLayoutManager(), + inSwitcher ? LayoutType.TAB_SWITCHER : LayoutType.BROWSING); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java index d72c902..817b97c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
@@ -530,6 +530,7 @@ waitForActivityStateChange(ActivityState.RESUMED, mActivity2, false); waitForActivityStateChange(ActivityState.RESUMED, mActivity1, true); + MultiInstanceManager.setTestDisplayIds(Collections.singletonList(0)); m1.setCurrentDisplayIdForTesting(0); m2.setCurrentDisplayIdForTesting(1);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java index d233903..596d6d8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
@@ -653,7 +653,8 @@ } }); - LayoutTestUtils.waitForLayout(mActivity.getLayoutManager(), LayoutType.TAB_SWITCHER); + LayoutTestUtils.waitForLayout(mActivity.getLayoutManager(), + shown ? LayoutType.TAB_SWITCHER : LayoutType.BROWSING); ThreadUtils.runOnUiThreadBlocking(mTestSupport::endAllAnimations); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java index 95bd9bec..89b2127 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/SceneOverlayTest.java
@@ -5,8 +5,6 @@ package org.chromium.chrome.browser.compositor.layouts; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; import android.content.Context; @@ -23,11 +21,9 @@ import org.robolectric.annotation.Config; import org.chromium.base.supplier.ObservableSupplier; -import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; -import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.SceneOverlay; import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; import org.chromium.chrome.browser.toolbar.bottom.ScrollingBottomViewSceneLayer; @@ -59,9 +55,6 @@ private ObservableSupplier<TabContentManager> mTabContentManagerSupplier; @Mock - private OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderOneshotSupplier; - - @Mock private TopUiThemeColorProvider mTopUiThemeColorProvider; private LayoutManagerImpl mLayoutManager; @@ -73,11 +66,9 @@ when(mLayoutManagerHost.getContext()).thenReturn(mContext); when(mContext.getResources()).thenReturn(mResources); when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); - doNothing().when(mLayoutStateProviderOneshotSupplier).set(any()); mLayoutManager = new LayoutManagerImpl(mLayoutManagerHost, mContainerView, - mTabContentManagerSupplier, null, mLayoutStateProviderOneshotSupplier, - () -> mTopUiThemeColorProvider); + mTabContentManagerSupplier, null, () -> mTopUiThemeColorProvider); } @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java index acf2d61..bdf6d7b1 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -99,6 +99,7 @@ LocationBarMediatorTest.GSAStateShadow.class, LocationBarMediatorTest.DownloadUtilsShadow.class}) @Features.EnableFeatures(ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH) +@Features.DisableFeatures(ChromeFeatureList.VOICE_BUTTON_IN_TOP_TOOLBAR) public class LocationBarMediatorTest { @Implements(UrlUtilities.class) static class ShadowUrlUtilities { @@ -897,6 +898,20 @@ @Test public void testButtonVisibility_phone() { + // Regression test for phones: toolbar mic visibility shouldn't impact the location + // bar mic. + verifyPhoneMicButtonVisibility(); + } + + @Test + @Features.EnableFeatures(ChromeFeatureList.VOICE_BUTTON_IN_TOP_TOOLBAR) + public void testButtonVisibility_toolbarMicEnabled_phone() { + // Regression test for phones: toolbar mic visibility shouldn't impact the location + // bar mic. + verifyPhoneMicButtonVisibility(); + } + + private void verifyPhoneMicButtonVisibility() { VoiceRecognitionHandler voiceRecognitionHandler = mock(VoiceRecognitionHandler.class); mMediator.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler); mMediator.onFinishNativeInitialization(); @@ -918,10 +933,39 @@ } @Test + public void testMicButtonVisibility_toolbarMicDisabled_tablet() { + verifyMicButtonVisibilityWhenFocusChanges(true); + } + + @Test + @Features.EnableFeatures(ChromeFeatureList.VOICE_BUTTON_IN_TOP_TOOLBAR) + public void testMicButtonVisibility_toolbarMicEnabled_tablet() { + verifyMicButtonVisibilityWhenFocusChanges(false); + } + + // Sets up and executes a test for visibility of a mic button on a tablet. + // The mic button should not be visible if toolbar mic is visible as well. + private void verifyMicButtonVisibilityWhenFocusChanges(boolean shouldBeVisible) { + VoiceRecognitionHandler voiceRecognitionHandler = mock(VoiceRecognitionHandler.class); + mTabletMediator.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler); + mTabletMediator.onFinishNativeInitialization(); + mTabletMediator.setShouldShowButtonsWhenUnfocusedForTablet(true); + mTabletMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true); + mTabletMediator.onUrlFocusChange(true); + doReturn("").when(mUrlCoordinator).getTextWithAutocomplete(); + doReturn(true).when(voiceRecognitionHandler).isVoiceSearchEnabled(); + Mockito.reset(mLocationBarTablet); + + mTabletMediator.updateButtonVisibility(); + verify(mLocationBarTablet).setMicButtonVisibility(shouldBeVisible); + } + + @Test public void testButtonVisibility_showMicUnfocused() { VoiceRecognitionHandler voiceRecognitionHandler = mock(VoiceRecognitionHandler.class); mMediator.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler); mMediator.onFinishNativeInitialization(); + mTabletMediator.setShouldShowButtonsWhenUnfocusedForTablet(false); mMediator.setShouldShowMicButtonWhenUnfocusedForPhone(true); doReturn(true).when(voiceRecognitionHandler).isVoiceSearchEnabled(); @@ -930,12 +974,37 @@ } @Test + public void testButtonVisibility_showMicUnfocused_toolbarMicDisabled_tablet() { + verifyMicButtonVisibilityWhenShowMicUnfocused(true); + } + + @Test + @Features.EnableFeatures(ChromeFeatureList.VOICE_BUTTON_IN_TOP_TOOLBAR) + public void testButtonVisibility_showMicUnfocused_toolbarMicEnabled_tablet() { + verifyMicButtonVisibilityWhenShowMicUnfocused(false); + } + + private void verifyMicButtonVisibilityWhenShowMicUnfocused(boolean shouldBeVisible) { + mTabletMediator.onFinishNativeInitialization(); + mTabletMediator.setShouldShowButtonsWhenUnfocusedForTablet(false); + mTabletMediator.setShouldShowMicButtonWhenUnfocusedForTesting(true); + VoiceRecognitionHandler voiceRecognitionHandler = mock(VoiceRecognitionHandler.class); + mTabletMediator.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler); + doReturn(true).when(voiceRecognitionHandler).isVoiceSearchEnabled(); + Mockito.reset(mLocationBarTablet); + + mTabletMediator.updateButtonVisibility(); + verify(mLocationBarTablet).setMicButtonVisibility(shouldBeVisible); + } + + @Test public void testButtonVisibility_tablet() { doReturn(mTab).when(mLocationBarDataProvider).getTab(); mTabletMediator.onFinishNativeInitialization(); Mockito.reset(mLocationBarTablet); mTabletMediator.updateButtonVisibility(); + verify(mLocationBarTablet).setMicButtonVisibility(false); verify(mLocationBarTablet).setBookmarkButtonVisibility(true); verify(mLocationBarTablet).setSaveOfflineButtonVisibility(true, true); } @@ -948,6 +1017,7 @@ Mockito.reset(mLocationBarTablet); mTabletMediator.updateButtonVisibility(); + verify(mLocationBarTablet).setMicButtonVisibility(false); verify(mLocationBarTablet).setBookmarkButtonVisibility(false); verify(mLocationBarTablet).setSaveOfflineButtonVisibility(false, true); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java index db64006..5833761 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java
@@ -144,7 +144,8 @@ private final TestSurveyController mTestSurveyController = new TestSurveyController(); - private String mPrefKey; + private String mPrefKeyPromptShown; + private String mPrefKeyDownloadAttempts; private SharedPreferencesManager mSharedPreferencesManager; private TabModelSelectorObserver mTabModelSelectorObserver; @@ -155,7 +156,8 @@ ShadowChromeFeatureList.sEnableSurvey = true; ShadowChromeFeatureList.sParamValues.put( ChromeSurveyController.SITE_ID_PARAM_NAME, TEST_TRIGGER_ID); - ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_NUMBER, "99"); + // By setting MAX_NUMBER to 1, #isRandomSelectedBySurvey is always true. + ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_NUMBER, "1"); ShadowInfoBarContainer.sInfoBarContainer = mMockInfoBarContainer; ShadowSurveyInfoBar.sShowInfoBarCallback = new PayloadCallbackHelper<>(); @@ -166,8 +168,11 @@ SurveyController.setInstanceForTesting(mTestSurveyController); ChromeSurveyController.forceIsUMAEnabledForTesting(true); - mPrefKey = ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey( - TEST_TRIGGER_ID); + mPrefKeyPromptShown = + ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey( + TEST_TRIGGER_ID); + mPrefKeyDownloadAttempts = + ChromePreferenceKeys.CHROME_SURVEY_DOWNLOAD_ATTEMPTS.createKey(TEST_TRIGGER_ID); mSharedPreferencesManager = SharedPreferencesManager.getInstance(); } @@ -176,6 +181,7 @@ ChromeSurveyController.forceIsUMAEnabledForTesting(false); ShadowChromeFeatureList.sParamValues.clear(); ShadowChromeFeatureList.sEnableSurvey = false; + ShadowRecordHistogram.reset(); CommandLine.getInstance().removeSwitch(ChromeSurveyController.COMMAND_LINE_PARAM_NAME); CommandLine.getInstance().removeSwitch(ChromeSwitches.CHROME_FORCE_ENABLE_SURVEY); @@ -210,31 +216,27 @@ @Test public void testStartDownloadIfEligibleTask() { + assertDownloadAttempted(false); initializeChromeSurveyController(); - - Assert.assertEquals("Download should be triggered.", 1, - mTestSurveyController.downloadIfApplicableCallback.getCallCount()); + assertDownloadAttempted(true); } @Test public void testStartDownloadIfEligibleTask_ShowedBefore() { CommandLine.getInstance().removeSwitch(ChromeSwitches.CHROME_FORCE_ENABLE_SURVEY); - mSharedPreferencesManager.writeLong(mPrefKey, 1000L); + mSharedPreferencesManager.writeLong(mPrefKeyPromptShown, 1000L); initializeChromeSurveyController(); - - Assert.assertEquals("Download should not trigger for user that has seen the survey prompt.", - 0, mTestSurveyController.downloadIfApplicableCallback.getCallCount()); + assertDownloadAttempted(false); } @Test public void testStartDownloadIfEligibleTask_ShowedBefore_ForceEnabled() { - mSharedPreferencesManager.writeLong(mPrefKey, 1000L); + mSharedPreferencesManager.writeLong(mPrefKeyPromptShown, 1000L); + assertDownloadAttempted(false); initializeChromeSurveyController(); - - Assert.assertEquals("Download should be triggered.", 1, - mTestSurveyController.downloadIfApplicableCallback.getCallCount()); + assertDownloadAttempted(true); } @Test @@ -244,9 +246,7 @@ ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, false); initializeChromeSurveyController(); - - Assert.assertEquals("Download should not be triggered.", 0, - mTestSurveyController.downloadIfApplicableCallback.getCallCount()); + assertDownloadAttempted(false); } @Test @@ -255,13 +255,52 @@ mSharedPreferencesManager.writeBoolean( ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, true); + assertDownloadAttempted(false); initializeChromeSurveyController(); + assertDownloadAttempted(true); + } - Assert.assertEquals("Download should not be triggered.", 1, + @Test + public void testStartDownloadIfEligibleTask_DownloadCapZero() { + CommandLine.getInstance().removeSwitch(ChromeSwitches.CHROME_FORCE_ENABLE_SURVEY); + ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_DOWNLOAD_ATTEMPTS, "0"); + + initializeChromeSurveyController(); + assertDownloadAttempted(true); + } + + @Test + public void testStartDownloadIfEligibleTask_DownloadWithinCap() { + CommandLine.getInstance().removeSwitch(ChromeSwitches.CHROME_FORCE_ENABLE_SURVEY); + ShadowChromeFeatureList.sParamValues.put( + ChromeSurveyController.MAX_DOWNLOAD_ATTEMPTS, "99"); + + assertDownloadAttempted(false); + initializeChromeSurveyController(); + assertDownloadAttempted(true); + } + + @Test + public void testStartDownloadIfEligibleTask_DownloadReachCap() { + CommandLine.getInstance().removeSwitch(ChromeSwitches.CHROME_FORCE_ENABLE_SURVEY); + ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_DOWNLOAD_ATTEMPTS, "2"); + mSharedPreferencesManager.writeInt(mPrefKeyDownloadAttempts, 2); + + initializeChromeSurveyController(); + Assert.assertEquals("Download should not be triggered.", 0, mTestSurveyController.downloadIfApplicableCallback.getCallCount()); } @Test + public void testStartDownloadIfEligibleTask_DownloadCapZero_ForceEnable() { + ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_DOWNLOAD_ATTEMPTS, "0"); + + assertDownloadAttempted(false); + initializeChromeSurveyController(); + assertDownloadAttempted(true); + } + + @Test public void testPresentSurvey_ValidTab_SurveyInfobarDelegate() { presentSurveyInfoBarInValidTab(); } @@ -353,6 +392,22 @@ surveyInfoBarDelegate.onSurveyTriggered(); assertInfoBarClosingStateRecorded(InfoBarClosingState.ACCEPTED_SURVEY); + assertDownloadAttemptRecordedWithSample(1); + assertInfoBarDisplayedRecorded(); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyTriggered_DownloadBefore() { + final int downloadAttempted = 3; + mSharedPreferencesManager.writeInt(mPrefKeyDownloadAttempts, downloadAttempted); + + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyTriggered(); + assertInfoBarClosingStateRecorded(InfoBarClosingState.ACCEPTED_SURVEY); + assertDownloadAttemptRecordedWithSample(downloadAttempted + 1); assertInfoBarDisplayedRecorded(); } @@ -499,11 +554,29 @@ private void assertInfoBarDisplayedRecorded() { Assert.assertTrue("SharedPreference for InfoBarShown is not recorded.", - mSharedPreferencesManager.contains(mPrefKey)); + SharedPreferencesManager.getInstance().contains(mPrefKeyPromptShown)); } private void assertInfoBarDisplayedNotRecorded(String reason) { - Assert.assertFalse(reason, mSharedPreferencesManager.contains(mPrefKey)); + Assert.assertFalse( + reason, SharedPreferencesManager.getInstance().contains(mPrefKeyPromptShown)); + } + + private void assertDownloadAttempted(boolean attempted) { + int expectedCount = attempted ? 1 : 0; + Assert.assertEquals("Times of download triggered does not match.", expectedCount, + mTestSurveyController.downloadIfApplicableCallback.getCallCount()); + Assert.assertEquals("Download attempt count is not recorded as expected.", expectedCount, + mSharedPreferencesManager.readInt(mPrefKeyDownloadAttempts)); + } + + private void assertDownloadAttemptRecordedWithSample(int sample) { + Assert.assertEquals(String.format("<Android.Survey.DownloadAttemptsBeforeAccepted> " + + "with sample <%d> is not recorded.", + sample), + 1, + ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.Survey.DownloadAttemptsBeforeAccepted", sample)); } private static class TestSurveyController extends SurveyController {
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni index 1823343..e2c5808 100644 --- a/chrome/android/modules/chrome_bundle_tmpl.gni +++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -168,6 +168,9 @@ is_multi_abi = _is_multi_abi validate_services = _enable_chrome_module + # For this to be respected, it must also be set on the base module target. + strip_unused_resources = is_official_build + # List of DFMs that are installed by default by wrapper scripts, to make # testing easier. This removes the need to manually specify, e.g., # "-m dev_ui" on every install or run.
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 8bdbb5f2..7830c2c 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-93.0.4530.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-93.0.4531.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 1f84d79..9d146edb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -295,6 +295,7 @@ <!-- Web app intent picker strings --> <if expr="is_win or is_macosx or is_linux"> <part file="protocol_handler_intent_picker_strings.grdp" /> + <part file="url_handler_intent_picker_strings.grdp" /> </if> <!-- Chrome-OS-specific strings --> @@ -10681,6 +10682,18 @@ <message name="IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_READ_PERMISSION_DIRECTORY_TEXT" desc="Text of dialog asking user if they intended to share a particular directory"> <ph name="ORIGIN">$1<ex>example.com</ex></ph> will be able to view files in <ph name="FOLDERNAME">$2<ex>My Project</ex></ph> until you close all tabs for this site </message> + <message name="IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_FILE_TEXT" desc="Text of the dialog for confirming origin scoped write access to files using the File System Access API"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> will be able to edit <ph name="FILENAME">$2<ex>README.md</ex></ph> + </message> + <message name="IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_DIRECTORY_TEXT" desc="Text of the dialog for confirming origin scoped write access to a directory using the File System Access API"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> will be able to edit files in <ph name="FOLDERNAME">$2<ex>My Project</ex></ph> + </message> + <message name="IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_FILE_TEXT" desc="Text of dialog for confirming read access to files using the File System Access API"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> will be able to view <ph name="FILENAME">$2<ex>README.md</ex></ph> + </message> + <message name="IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_DIRECTORY_TEXT" desc="Text of dialog asking user if they intended to share a particular directory"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> will be able to view files in <ph name="FOLDERNAME">$2<ex>My Project</ex></ph> + </message> <message name="IDS_FILE_SYSTEM_ACCESS_EDIT_FILE_PERMISSION_TITLE" desc="Title of dialog asking user to confirm giving read and write access to a file using the File System Access API"> Let site edit <ph name="FILE_NAME">$1<ex>README.md</ex></ph>? </message>
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_DIRECTORY_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_DIRECTORY_TEXT.png.sha1 new file mode 100644 index 0000000..d54bef3 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_DIRECTORY_TEXT.png.sha1
@@ -0,0 +1 @@ +ec3f53e330829c5e749574ffa5ac0bf8bcf64752 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_FILE_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_FILE_TEXT.png.sha1 new file mode 100644 index 0000000..f736c56a --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_FILE_TEXT.png.sha1
@@ -0,0 +1 @@ +c4aef23649559effb8eecd04f301beae0cd354c7 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_DIRECTORY_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_DIRECTORY_TEXT.png.sha1 new file mode 100644 index 0000000..03a3c654 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_DIRECTORY_TEXT.png.sha1
@@ -0,0 +1 @@ +0c665834063c633ea0ea92b3bd0eae57bf1500d6 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_FILE_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_FILE_TEXT.png.sha1 new file mode 100644 index 0000000..7d672f6 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_FILE_TEXT.png.sha1
@@ -0,0 +1 @@ +8ae5add6abe1c825fd9083853abf1e6978d9c6ee \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings.grdp b/chrome/app/url_handler_intent_picker_strings.grdp new file mode 100644 index 0000000..76ee4d85 --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings.grdp
@@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- URL-Handler-Intent-Picker strings (included from generated_resources.grd). --> +<grit-part> + <message name="IDS_URL_HANDLER_INTENT_PICKER_TITLE" desc="Title for the URL handler intent picker."> + Which application do you want to use? + </message> + <message name="IDS_URL_HANDLER_INTENT_PICKER_REMEMBER_SELECTION" desc="Label for the checkbox in the URL handler intent picker to save the current selection so that the URL handler intent picker will not be shown again."> + Remember my choice + </message> + <message name="IDS_URL_HANDLER_INTENT_PICKER_OK_BUTTON_TEXT" desc="Label for the button in the URL handler intent picker dialog that dismisses the dialog and launches an application or the browser."> + Open + </message> + <message name="IDS_URL_HANDLER_INTENT_PICKER_CANCEL_BUTTON_TEXT" desc="Label for the button in the URL handler intent picker dialog that dismisses the dialog and does not launch an application."> + Cancel + </message> + <message name="IDS_URL_HANDLER_INTENT_PICKER_APP_TITLE" desc="Title for an appplication with profile name as an option in the URL handler intent picker dialog."> + <ph name="APP_NAME">$1<ex>Demo App</ex></ph> (<ph name="PROFILE_NAME">$2<ex>Work</ex></ph>) + </message> + <message name="IDS_URL_HANDLER_INTENT_PICKER_APP_ORIGIN_LABEL" desc="Label for the url origin of each item in the web app list in the URL handler intent picker dialog"> + Publisher: <ph name="APP_ORIGIN">$1<ex>example.com</ex></ph> + </message> +</grit-part> \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_ORIGIN_LABEL.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_ORIGIN_LABEL.png.sha1 new file mode 100644 index 0000000..96cd31a --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_ORIGIN_LABEL.png.sha1
@@ -0,0 +1 @@ +40a13b6251935c0554ef427b641e21d2f7e28888 \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_TITLE.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_TITLE.png.sha1 new file mode 100644 index 0000000..a6589cf --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_APP_TITLE.png.sha1
@@ -0,0 +1 @@ +9608d55671802fd8ae3c2b4b2a86647c7b40f24e \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_CANCEL_BUTTON_TEXT.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_CANCEL_BUTTON_TEXT.png.sha1 new file mode 100644 index 0000000..5d3f120 --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_CANCEL_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@ +342612bcf19974912ad7d228806c4d73689e4ebd \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_OK_BUTTON_TEXT.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_OK_BUTTON_TEXT.png.sha1 new file mode 100644 index 0000000..cd3c299 --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_OK_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@ +ef4966e91c84df1d2cce46336610042b22acd33f \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_REMEMBER_SELECTION.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_REMEMBER_SELECTION.png.sha1 new file mode 100644 index 0000000..30a3413 --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_REMEMBER_SELECTION.png.sha1
@@ -0,0 +1 @@ +9afee1a236cb08a50a63278cd1b83b5677e71cbb \ No newline at end of file
diff --git a/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_TITLE.png.sha1 b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_TITLE.png.sha1 new file mode 100644 index 0000000..e197462 --- /dev/null +++ b/chrome/app/url_handler_intent_picker_strings_grdp/IDS_URL_HANDLER_INTENT_PICKER_TITLE.png.sha1
@@ -0,0 +1 @@ +70bfb6eec8119a51ace9de1175e0196e2926d76e \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index bfd9846..57b2312 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1662,12 +1662,6 @@ "site_isolation/site_details.h", "speech/chrome_speech_recognition_manager_delegate.cc", "speech/chrome_speech_recognition_manager_delegate.h", - "speech/network_speech_recognizer.cc", - "speech/network_speech_recognizer.h", - "speech/speech_recognizer.cc", - "speech/speech_recognizer.h", - "speech/speech_recognizer_delegate.cc", - "speech/speech_recognizer_delegate.h", "ssl/certificate_error_reporter.cc", "ssl/certificate_error_reporter.h", "ssl/chrome_security_blocking_page_factory.cc", @@ -4570,8 +4564,13 @@ "speech/cros_speech_recognition_service.h", "speech/cros_speech_recognition_service_factory.cc", "speech/cros_speech_recognition_service_factory.h", + "speech/network_speech_recognizer.cc", + "speech/network_speech_recognizer.h", "speech/on_device_speech_recognizer.cc", "speech/on_device_speech_recognizer.h", + "speech/speech_recognizer.cc", + "speech/speech_recognizer.h", + "speech/speech_recognizer_delegate.h", "speech/tts_chromeos.cc", "speech/tts_chromeos.h", "speech/tts_controller_delegate_impl.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index e2eb9acdc..6034ac6 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -188,6 +188,7 @@ #include "ui/events/event_switches.h" #include "ui/gfx/switches.h" #include "ui/gl/buildflags.h" +#include "ui/gl/gl_features.h" #include "ui/gl/gl_switches.h" #include "ui/native_theme/native_theme_features.h" @@ -5160,13 +5161,6 @@ flag_descriptions::kEnableAssistantAppSupportDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::assistant::features::kAssistantAppSupport)}, - {"enable-assistant-media-session-integration", - flag_descriptions::kEnableAssistantMediaSessionIntegrationName, - flag_descriptions::kEnableAssistantMediaSessionIntegrationDescription, - kOsCrOS, - FEATURE_VALUE_TYPE( - chromeos::assistant::features::kEnableMediaSessionIntegration)}, - {"enable-quick-answers", flag_descriptions::kEnableQuickAnswersName, flag_descriptions::kEnableQuickAnswersDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kQuickAnswers)}, @@ -5467,10 +5461,6 @@ flag_descriptions::kMeteredShowToggleDescription, kOsCrOS, FEATURE_VALUE_TYPE(features::kMeteredShowToggle)}, - {"printer-status-dialog", flag_descriptions::kPrinterStatusDialogName, - flag_descriptions::kPrinterStatusDialogDescription, kOsCrOS, - FEATURE_VALUE_TYPE(chromeos::features::kPrinterStatusDialog)}, - {"wifi-sync-allow-deletes", flag_descriptions::kWifiSyncAllowDeletesName, flag_descriptions::kWifiSyncAllowDeletesDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kWifiSyncAllowDeletes)}, @@ -5510,10 +5500,6 @@ flag_descriptions::kSelectToSpeakNavigationControlDescription, kOsCrOS, FEATURE_VALUE_TYPE(features::kSelectToSpeakNavigationControl)}, - {"print-server-scaling", flag_descriptions::kPrintServerScalingName, - flag_descriptions::kPrintServerScalingDescription, kOsCrOS, - FEATURE_VALUE_TYPE(chromeos::features::kPrintServerScaling)}, - {"enable-networking-in-diagnostics-app", flag_descriptions::kEnableNetworkingInDiagnosticsAppName, flag_descriptions::kEnableNetworkingInDiagnosticsAppDescription, kOsCrOS, @@ -7217,6 +7203,12 @@ FEATURE_VALUE_TYPE(ash::features::kWebApkGenerator)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) + {"use-passthrough-command-decoder", + flag_descriptions::kUsePassthroughCommandDecoderName, + flag_descriptions::kUsePassthroughCommandDecoderDescription, + kOsMac | kOsLinux | kOsCrOS | kOsAndroid, + FEATURE_VALUE_TYPE(features::kDefaultPassthroughCommandDecoder)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/accessibility/live_caption_controller.cc b/chrome/browser/accessibility/live_caption_controller.cc index 83cec98..e4e58e9 100644 --- a/chrome/browser/accessibility/live_caption_controller.cc +++ b/chrome/browser/accessibility/live_caption_controller.cc
@@ -211,7 +211,7 @@ bool LiveCaptionController::DispatchTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, - const media::mojom::SpeechRecognitionResultPtr& result) { + const media::SpeechRecognitionResult& result) { if (!caption_bubble_controller_) return false; return caption_bubble_controller_->OnTranscription(
diff --git a/chrome/browser/accessibility/live_caption_controller.h b/chrome/browser/accessibility/live_caption_controller.h index cc7ba37..4b917f5 100644 --- a/chrome/browser/accessibility/live_caption_controller.h +++ b/chrome/browser/accessibility/live_caption_controller.h
@@ -58,7 +58,7 @@ // this returns false. bool DispatchTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, - const media::mojom::SpeechRecognitionResultPtr& result); + const media::SpeechRecognitionResult& result); void OnLanguageIdentificationEvent( const media::mojom::LanguageIdentificationEventPtr& event);
diff --git a/chrome/browser/accessibility/live_caption_controller_browsertest.cc b/chrome/browser/accessibility/live_caption_controller_browsertest.cc index 54e616c..42582573 100644 --- a/chrome/browser/accessibility/live_caption_controller_browsertest.cc +++ b/chrome/browser/accessibility/live_caption_controller_browsertest.cc
@@ -127,7 +127,7 @@ bool DispatchTranscriptionToProfile(std::string text, Profile* profile) { return GetControllerForProfile(profile)->DispatchTranscription( GetLiveCaptionSpeechRecognitionHost(), - media::mojom::SpeechRecognitionResult::New(text, false /* is_final */)); + media::SpeechRecognitionResult(text, /* is_final */ false)); } void OnError() { OnErrorOnProfile(browser()->profile()); }
diff --git a/chrome/browser/accessibility/live_caption_speech_recognition_host.cc b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc index bacff63..6543a22 100644 --- a/chrome/browser/accessibility/live_caption_speech_recognition_host.cc +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.cc
@@ -42,7 +42,7 @@ } void LiveCaptionSpeechRecognitionHost::OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResultPtr result, + const media::SpeechRecognitionResult& result, OnSpeechRecognitionRecognitionEventCallback reply) { LiveCaptionController* live_caption_controller = GetLiveCaptionController(); if (!live_caption_controller) {
diff --git a/chrome/browser/accessibility/live_caption_speech_recognition_host.h b/chrome/browser/accessibility/live_caption_speech_recognition_host.h index 3db8765..0f04d9b 100644 --- a/chrome/browser/accessibility/live_caption_speech_recognition_host.h +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host.h
@@ -44,7 +44,7 @@ // media::mojom::SpeechRecognitionRecognizerClient: void OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResultPtr result, + const media::SpeechRecognitionResult& result, OnSpeechRecognitionRecognitionEventCallback reply) override; void OnLanguageIdentificationEvent( media::mojom::LanguageIdentificationEventPtr event) override;
diff --git a/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc b/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc index 43691376..3ed4faf 100644 --- a/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc +++ b/chrome/browser/accessibility/live_caption_speech_recognition_host_browsertest.cc
@@ -68,7 +68,7 @@ std::string text, bool expected_success) { remotes_[frame_host]->OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResult::New(text, /*is_final=*/false), + media::SpeechRecognitionResult(text, /*is_final=*/false), base::BindOnce(&LiveCaptionSpeechRecognitionHostTest:: DispatchTranscriptionCallback, base::Unretained(this), expected_success));
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index ed25985..4e502e8 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -287,7 +287,14 @@ if (icon_url == shortcut_info.splash_image_url.spec()) { if (shortcut_info.splash_image_url != shortcut_info.best_primary_icon_url) { - image->set_image_data(it->second.unsafe_data); + // WebAPK updates uses the image data from fetched bitmap; installs use + // the image data from icon_url_to_murmur2_hash. + if (!splash_icon.drawsNothing()) { + SetImageData(image, splash_icon); + } else { + image->set_image_data(it->second.unsafe_data); + } + if (shortcut_info.is_splash_image_maskable) { image->add_purposes(webapk::Image::MASKABLE); } else {
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc index 890462a..cc7b81e 100644 --- a/chrome/browser/android/webapk/webapk_installer_unittest.cc +++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -604,8 +604,7 @@ manifest.icons(1).hash()); EXPECT_THAT(manifest.icons(1).usages(), testing::ElementsAre(webapk::Image::SPLASH_ICON)); - EXPECT_EQ(icon_url_to_murmur2_hash[best_splash_icon_url].unsafe_data, - manifest.icons(1).image_data()); + EXPECT_TRUE(manifest.icons(1).has_image_data()); // Check protobuf fields for unused icon. EXPECT_EQ(kUnusedIconPath, manifest.icons(2).src()); @@ -775,8 +774,6 @@ EXPECT_THAT(manifest.icons(1).usages(), testing::ElementsAre(webapk::Image::SPLASH_ICON)); EXPECT_TRUE(manifest.icons(1).has_image_data()); - EXPECT_EQ(manifest.icons(1).image_data(), - icon_url_to_murmur2_hash[best_icon_url].unsafe_data); // Check protobuf fields for unused icon. EXPECT_EQ(kUnusedIconPath, manifest.icons(2).src());
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 25ead0e2..6e0338f 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -310,6 +310,27 @@ /*ignore_profile_picker=*/true); } +// Open the urls in the last used browser from a regular profile. +void OpenUrlsInBrowser(const std::vector<GURL>& urls, + Profile* safe_last_profile) { + Profile* profile = + g_browser_process->profile_manager()->GetLastUsedProfileAllowedByPolicy(); + Browser* browser = chrome::FindLastActiveWithProfile(profile); + // if no browser window exists then create one with no tabs to be filled in + if (!browser) { + browser = Browser::Create( + Browser::CreateParams(safe_last_profile, /*user_gesture=*/true)); + browser->window()->Show(); + } + + base::CommandLine dummy(base::CommandLine::NO_PROGRAM); + chrome::startup::IsFirstRun first_run = + first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN + : chrome::startup::IS_NOT_FIRST_RUN; + StartupBrowserCreatorImpl launch(base::FilePath(), dummy, first_run); + launch.OpenURLsInBrowser(browser, false, urls); +} + } // namespace // Returns the last profile. This is extracted as a standalone function in order @@ -1559,26 +1580,9 @@ return; } - if (StartupBrowserCreator::MaybeHandleProfileAgnosticUrls(urls)) - return; - - // Pick the last used browser from a regular profile to open the urls. - Profile* profile = - g_browser_process->profile_manager()->GetLastUsedProfileAllowedByPolicy(); - Browser* browser = chrome::FindLastActiveWithProfile(profile); - // if no browser window exists then create one with no tabs to be filled in - if (!browser) { - browser = Browser::Create( - Browser::CreateParams([self safeLastProfileForNewWindows], true)); - browser->window()->Show(); - } - - base::CommandLine dummy(base::CommandLine::NO_PROGRAM); - chrome::startup::IsFirstRun first_run = - first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN - : chrome::startup::IS_NOT_FIRST_RUN; - StartupBrowserCreatorImpl launch(base::FilePath(), dummy, first_run); - launch.OpenURLsInBrowser(browser, false, urls); + StartupBrowserCreator::MaybeHandleProfileAgnosticUrls( + urls, base::BindOnce(&OpenUrlsInBrowser, urls, + [self safeLastProfileForNewWindows])); } - (void)getUrl:(NSAppleEventDescriptor*)event
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm index d23dfe4..668e94f 100644 --- a/chrome/browser/app_controller_mac_browsertest.mm +++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -76,10 +76,14 @@ #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "extensions/browser/app_window/app_window_registry.h" +#include "extensions/browser/extension_dialog_auto_confirm.h" #include "extensions/common/extension.h" #include "extensions/test/extension_test_message_listener.h" #include "net/test/embedded_test_server/embedded_test_server.h" #import "ui/events/test/cocoa_test_event_utils.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" using base::SysUTF16ToNSString; @@ -156,6 +160,12 @@ return CreateAndWaitForProfile(ProfileManager::GetSystemProfilePath()); } +void AutoCloseDialog(views::Widget* widget) { + // Call CancelDialog to close the dialog, but the actual behavior will be + // determined by the ScopedTestDialogAutoConfirm configs. + views::test::CancelDialog(widget); +} + } // namespace @interface TestOpenShortcutOnStartup : NSObject @@ -946,7 +956,9 @@ }; IN_PROC_BROWSER_TEST_F(StartupWebAppUrlHandlingBrowserTest, - WebAppLaunch_InScopeUrl) { + DialogCancelled_NoLaunch) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); apps::UrlHandlerInfo url_handler; url_handler.origin = url::Origin::Create(GURL(kStartUrl)); @@ -955,6 +967,62 @@ // Start URL is in app scope. SendAppleEventToOpenUrlToAppController(GURL(kStartUrl)); + // The waiter will get the dialog when it shows up and close it. + waiter.WaitIfNeededAndGet()->CloseWithReason( + views::Widget::ClosedReason::kEscKeyPressed); + + // Wait for app launch task to complete. + content::RunAllTasksUntilIdle(); + + // When dialog is closed, nothing will happen. + ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); + ASSERT_FALSE(web_app::AppBrowserController::IsForWebApp(browser(), app_id)); +} + +IN_PROC_BROWSER_TEST_F(StartupWebAppUrlHandlingBrowserTest, + DialogAccepted_BrowserLaunch) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); + + apps::UrlHandlerInfo url_handler; + url_handler.origin = url::Origin::Create(GURL(kStartUrl)); + + web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + + // Select the first choice, which is the browser. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 0); + SendAppleEventToOpenUrlToAppController(GURL(kStartUrl)); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); + + // Wait for browser launch task to complete. + content::RunAllTasksUntilIdle(); + + ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); + ASSERT_FALSE(web_app::AppBrowserController::IsForWebApp(browser(), app_id)); + TabStripModel* tab_strip = browser()->tab_strip_model(); + ASSERT_EQ(2, tab_strip->count()); + // Check the link of the new tab that was opened. + content::WebContents* web_contents = tab_strip->GetWebContentsAt(1); + EXPECT_EQ(GURL(kStartUrl), web_contents->GetVisibleURL()); +} + +IN_PROC_BROWSER_TEST_F(StartupWebAppUrlHandlingBrowserTest, + DialogAccepted_WebAppLaunch_InScopeUrl) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); + apps::UrlHandlerInfo url_handler; + url_handler.origin = url::Origin::Create(GURL(kStartUrl)); + + web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + + // Select the second choice, which is the app. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 1); + // kStartUrl is in app scope. + SendAppleEventToOpenUrlToAppController(GURL(kStartUrl)); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); + // Wait for app launch task to complete. content::RunAllTasksUntilIdle(); @@ -965,7 +1033,6 @@ ASSERT_TRUE(app_browser); ASSERT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id)); - // Verify the launched URL of the app window. TabStripModel* tab_strip = app_browser->tab_strip_model(); ASSERT_EQ(1, tab_strip->count()); content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); @@ -973,13 +1040,20 @@ } IN_PROC_BROWSER_TEST_F(StartupWebAppUrlHandlingBrowserTest, - WebAppLaunch_DifferentOriginUrl) { + DialogAccepted_WebAppLaunch_DifferentOriginUrl) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); apps::UrlHandlerInfo url_handler; url_handler.origin = url::Origin::Create(GURL("https://example.com")); web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + // Select the second choice, which is the app. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 1); + // URL is not in app scope but matches url_handlers of installed app. SendAppleEventToOpenUrlToAppController(GURL("https://example.com/abc/def")); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); // Wait for app launch task to complete. content::RunAllTasksUntilIdle();
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_watch_apitest.cc b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_watch_apitest.cc index b7a1f95..a30226e 100644 --- a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_watch_apitest.cc +++ b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_watch_apitest.cc
@@ -214,8 +214,16 @@ ExecuteCmdAndCheckReply(kRemoveGalleryWatchCmd, kRemoveGalleryWatchOK); } +// TODO(crbug.com/1047645): Flaky on Linux and Windows. +#if defined(OS_LINUX) || defined(OS_WIN) +#define MAYBE_CorrectResponseOnModifyingWatchedGallery \ + DISABLED_CorrectResponseOnModifyingWatchedGallery +#else +#define MAYBE_CorrectResponseOnModifyingWatchedGallery \ + CorrectResponseOnModifyingWatchedGallery +#endif IN_PROC_BROWSER_TEST_F(MediaGalleriesGalleryWatchApiTest, - CorrectResponseOnModifyingWatchedGallery) { + MAYBE_CorrectResponseOnModifyingWatchedGallery) { if (!GalleryWatchesSupported()) return;
diff --git a/chrome/browser/ash/accessibility/dictation.cc b/chrome/browser/ash/accessibility/dictation.cc index 54d76289..38413fd 100644 --- a/chrome/browser/ash/accessibility/dictation.cc +++ b/chrome/browser/ash/accessibility/dictation.cc
@@ -135,8 +135,7 @@ void Dictation::OnSpeechResult( const std::u16string& transcription, bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& - word_offsets) { + const absl::optional<media::SpeechRecognitionResult>& word_offsets) { // If the first character of text isn't a space, add a space before it. // NetworkSpeechRecognizer adds the preceding space but // OnDeviceSpeechRecognizer does not. This is also done in
diff --git a/chrome/browser/ash/accessibility/dictation.h b/chrome/browser/ash/accessibility/dictation.h index af1c751..6e6faaa 100644 --- a/chrome/browser/ash/accessibility/dictation.h +++ b/chrome/browser/ash/accessibility/dictation.h
@@ -38,11 +38,10 @@ friend class DictationTest; // SpeechRecognizerDelegate: - void OnSpeechResult( - const std::u16string& transcription, - bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& - word_offsets) override; + void OnSpeechResult(const std::u16string& transcription, + bool is_final, + const absl::optional<media::SpeechRecognitionResult>& + full_result) override; void OnSpeechSoundLevelChanged(int16_t level) override; void OnSpeechRecognitionStateChanged( SpeechRecognizerStatus new_state) override;
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc index f7b52a35..b17c58f 100644 --- a/chrome/browser/ash/accessibility/dictation_browsertest.cc +++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -153,7 +153,7 @@ EXPECT_TRUE(fake_service_->is_capturing_audio()); base::RunLoop loop; fake_service_->SendSpeechRecognitionResult( - media::mojom::SpeechRecognitionResult::New(result, is_final)); + media::SpeechRecognitionResult(result, is_final)); loop.RunUntilIdle(); } }
diff --git a/chrome/browser/ash/borealis/borealis_app_launcher.cc b/chrome/browser/ash/borealis/borealis_app_launcher.cc index e04d8d0f..ff44730 100644 --- a/chrome/browser/ash/borealis/borealis_app_launcher.cc +++ b/chrome/browser/ash/borealis/borealis_app_launcher.cc
@@ -29,11 +29,9 @@ const std::string& app_id, const std::vector<std::string>& args, OnLaunchedCallback callback) { - // Do not launch anything when using the installer app. - // - // TODO(b/170677773): Launch a _certain_ application... + // Launching the borealis app is a legacy way of launching its main app if (app_id == kBorealisAppId) { - std::move(callback).Run(LaunchResult::kSuccess); + Launch(ctx, kBorealisMainAppId, args, std::move(callback)); return; }
diff --git a/chrome/browser/ash/borealis/borealis_app_launcher_unittest.cc b/chrome/browser/ash/borealis/borealis_app_launcher_unittest.cc index 708274d..eef1a1d 100644 --- a/chrome/browser/ash/borealis/borealis_app_launcher_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_app_launcher_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/base64.h" #include "base/bind.h" #include "base/test/bind.h" #include "chrome/browser/ash/borealis/borealis_context.h" @@ -55,8 +56,8 @@ public: BorealisAppLauncherTest() : ctx_(BorealisContext::CreateBorealisContextForTesting(&profile_)) { - ctx_->set_vm_name("test_vm_name"); - ctx_->set_container_name("test_container_name"); + ctx_->set_vm_name("borealis"); + ctx_->set_container_name("penguin"); } protected: @@ -89,10 +90,27 @@ std::unique_ptr<BorealisContext> ctx_; }; -TEST_F(BorealisAppLauncherTest, LauncherAppAlwaysWorks) { +TEST_F(BorealisAppLauncherTest, LauncherAppLaunchesMainApp) { CallbackFactory callback_check; + + // We add the main app to the registry, so that it will be launched. + std::string desktop_file_id; + ASSERT_TRUE(base::Base64Decode("c3RlYW0=", &desktop_file_id)); + ASSERT_EQ(SetDummyApp(desktop_file_id), kBorealisMainAppId); + EXPECT_CALL(callback_check, Call(BorealisAppLauncher::LaunchResult::kSuccess)); + Cicerone()->SetOnLaunchContainerApplicationCallback( + base::BindLambdaForTesting( + [&](const vm_tools::cicerone::LaunchContainerApplicationRequest& + request, + chromeos::DBusMethodCallback< + vm_tools::cicerone::LaunchContainerApplicationResponse> + callback) { + vm_tools::cicerone::LaunchContainerApplicationResponse response; + response.set_success(true); + std::move(callback).Run(response); + })); BorealisAppLauncher::Launch(Context(), kBorealisAppId, callback_check.BindOnce()); }
diff --git a/chrome/browser/ash/borealis/borealis_context_manager_mock.h b/chrome/browser/ash/borealis/borealis_context_manager_mock.h index dbc4483..e7639718 100644 --- a/chrome/browser/ash/borealis/borealis_context_manager_mock.h +++ b/chrome/browser/ash/borealis/borealis_context_manager_mock.h
@@ -14,7 +14,7 @@ public: BorealisContextManagerMock(); - ~BorealisContextManagerMock(); + ~BorealisContextManagerMock() override; MOCK_METHOD(void, StartBorealis,
diff --git a/chrome/browser/ash/borealis/borealis_installer.cc b/chrome/browser/ash/borealis/borealis_installer.cc index 3b2ef73..e4d3611b3 100644 --- a/chrome/browser/ash/borealis/borealis_installer.cc +++ b/chrome/browser/ash/borealis/borealis_installer.cc
@@ -17,6 +17,10 @@ return "kInactive"; case InstallingState::kInstallingDlc: return "kInstallingDlc"; + case InstallingState::kStartingUp: + return "kStartingUp"; + case InstallingState::kAwaitingApplications: + return "kAwaitingApplications"; } }
diff --git a/chrome/browser/ash/borealis/borealis_installer.h b/chrome/browser/ash/borealis/borealis_installer.h index c7a0e9ad..1553dfc6 100644 --- a/chrome/browser/ash/borealis/borealis_installer.h +++ b/chrome/browser/ash/borealis/borealis_installer.h
@@ -22,6 +22,8 @@ enum class InstallingState { kInactive, kInstallingDlc, + kStartingUp, + kAwaitingApplications, }; // Observer class for the Borealis installation related events.
diff --git a/chrome/browser/ash/borealis/borealis_installer_impl.cc b/chrome/browser/ash/borealis/borealis_installer_impl.cc index 987a025d..49c68f0 100644 --- a/chrome/browser/ash/borealis/borealis_installer_impl.cc +++ b/chrome/browser/ash/borealis/borealis_installer_impl.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "chrome/browser/ash/borealis/borealis_context_manager.h" #include "chrome/browser/ash/borealis/borealis_features.h" #include "chrome/browser/ash/borealis/borealis_metrics.h" @@ -29,17 +30,32 @@ namespace borealis { +namespace { + +// Time to wait for borealis' main app to appear. This is done almost +// immediately by garcon on launch so a short timeout is sufficient. +constexpr base::TimeDelta kWaitForMainAppTimeout = + base::TimeDelta::FromSeconds(5); + +} // namespace + class BorealisInstallerImpl::Installation : public Transition<BorealisInstallerImpl::InstallInfo, BorealisInstallerImpl::InstallInfo, - BorealisInstallResult> { + BorealisInstallResult>, + public guest_os::GuestOsRegistryService::Observer { public: - explicit Installation( + Installation( + Profile* profile, + base::TimeDelta main_app_timeout, base::RepeatingCallback<void(double)> update_progress_callback, base::RepeatingCallback<void(InstallingState)> update_state_callback) - : installation_start_tick_(base::TimeTicks::Now()), + : profile_(profile), + installation_start_tick_(base::TimeTicks::Now()), + main_app_timeout_(main_app_timeout), update_progress_callback_(std::move(update_progress_callback)), update_state_callback_(std::move(update_state_callback)), + apps_observation_(this), weak_factory_(this) {} base::TimeTicks start_time() { return installation_start_tick_; } @@ -76,7 +92,12 @@ // If success, continue to the next state. if (install_result.error == dlcservice::kErrorNone) { - Succeed(std::move(install_info_)); + // We are in the callback of DLC completion, and the first thing startup + // will do is try to mount the DLC, so we need to use a PostTask to avoid + // deadlocking ourselves. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&Installation::StartupBorealis, + weak_factory_.GetWeakPtr())); return; } @@ -112,11 +133,91 @@ Fail(result); } + // As part of its installation we perform a dry run of borealis. This ensures + // that the VM works somewhat and allows the container_guest daemon to update + // Chrome. See go/borealis-mid-launch for details. + void StartupBorealis() { + SetState(InstallingState::kStartingUp); + BorealisService::GetForProfile(profile_)->ContextManager().StartBorealis( + base::BindOnce(&Installation::OnBorealisStarted, + weak_factory_.GetWeakPtr())); + } + + void OnBorealisStarted(BorealisContextManager::ContextOrFailure result) { + if (result) { + WaitForMainApp(); + return; + } + LOG(ERROR) << "Failed to start borealis (code " + << static_cast<int>(result.Error().error()) + << "): " << result.Error().description(); + Fail(BorealisInstallResult::kStartupFailed); + } + + void WaitForMainApp() { + SetState(InstallingState::kAwaitingApplications); + guest_os::GuestOsRegistryService* apps_registry = + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile_); + apps_observation_.Observe(apps_registry); + absl::optional<guest_os::GuestOsRegistryService::Registration> main_app = + apps_registry->GetRegistration(kBorealisMainAppId); + if (main_app.has_value() && main_app->VmType() == + guest_os::GuestOsRegistryService::VmType:: + ApplicationList_VmType_BOREALIS) { + apps_observation_.Reset(); + MainAppFound(true); + return; + } + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&Installation::MainAppFound, weak_factory_.GetWeakPtr(), + false), + main_app_timeout_); + } + + void OnRegistryUpdated( + guest_os::GuestOsRegistryService* registry_service, + guest_os::GuestOsRegistryService::VmType vm_type, + const std::vector<std::string>& updated_apps, + const std::vector<std::string>& removed_apps, + const std::vector<std::string>& inserted_apps) override { + if (vm_type != guest_os::GuestOsRegistryService::VmType:: + ApplicationList_VmType_BOREALIS) { + return; + } + + for (const auto& app : inserted_apps) { + if (app == kBorealisMainAppId) { + MainAppFound(true); + break; + } + } + } + + void MainAppFound(bool found) { + // We use the presence of the install_info_ object to prevent races here, so + // return if it has already been removed. + if (!install_info_) + return; + if (!found) { + install_info_.reset(); + LOG(ERROR) << "Failed to verify that the main app has been created"; + Fail(BorealisInstallResult::kMainAppNotPresent); + return; + } + Succeed(std::move(install_info_)); + } + + Profile* const profile_; base::TimeTicks installation_start_tick_; + base::TimeDelta main_app_timeout_; InstallingState installing_state_; base::RepeatingCallback<void(double)> update_progress_callback_; base::RepeatingCallback<void(InstallingState)> update_state_callback_; std::unique_ptr<BorealisInstallerImpl::InstallInfo> install_info_; + base::ScopedObservation<guest_os::GuestOsRegistryService, + guest_os::GuestOsRegistryService::Observer> + apps_observation_; base::WeakPtrFactory<Installation> weak_factory_; }; @@ -206,7 +307,9 @@ }; BorealisInstallerImpl::BorealisInstallerImpl(Profile* profile) - : profile_(profile), weak_ptr_factory_(this) {} + : profile_(profile), + main_app_timeout_(kWaitForMainAppTimeout), + weak_ptr_factory_(this) {} BorealisInstallerImpl::~BorealisInstallerImpl() = default; @@ -244,6 +347,7 @@ install_info->vm_name = "borealis"; install_info->container_name = "penguin"; in_progress_installation_ = std::make_unique<Installation>( + profile_, main_app_timeout_, base::BindRepeating(&BorealisInstallerImpl::UpdateProgress, weak_ptr_factory_.GetWeakPtr()), base::BindRepeating(&BorealisInstallerImpl::UpdateInstallingState, @@ -293,6 +397,11 @@ observers_.RemoveObserver(observer); } +void BorealisInstallerImpl::SetMainAppTimeoutForTesting( + base::TimeDelta timeout) { + main_app_timeout_ = timeout; +} + void BorealisInstallerImpl::UpdateProgress(double state_progress) { if (state_progress < 0 || state_progress > 1) { LOG(ERROR) << "Unexpected progress value " << state_progress @@ -306,7 +415,15 @@ switch (installing_state_) { case InstallingState::kInstallingDlc: start_range = 0; - end_range = 1; + end_range = 0.5; + break; + case InstallingState::kStartingUp: + start_range = 0.5; + end_range = 0.8; + break; + case InstallingState::kAwaitingApplications: + start_range = 0.8; + end_range = 1.0; break; case InstallingState::kInactive: NOTREACHED(); @@ -327,6 +444,8 @@ for (auto& observer : observers_) { observer.OnStateUpdated(installing_state_); } + // The state just changed, so the progress towards that state is 0. + UpdateProgress(0); } void BorealisInstallerImpl::OnInstallComplete( @@ -349,6 +468,7 @@ profile_->GetPrefs()->SetBoolean(prefs::kBorealisInstalledOnDevice, true); RecordBorealisInstallOverallTimeHistogram(duration); } + // TODO(b/188713071): Clean up if installation fails. RecordBorealisInstallResultHistogram(result); } for (auto& observer : observers_) {
diff --git a/chrome/browser/ash/borealis/borealis_installer_impl.h b/chrome/browser/ash/borealis/borealis_installer_impl.h index a92d42c..4f841f9 100644 --- a/chrome/browser/ash/borealis/borealis_installer_impl.h +++ b/chrome/browser/ash/borealis/borealis_installer_impl.h
@@ -43,6 +43,9 @@ void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; + // Override the timeout to wait for the main app to appear. + void SetMainAppTimeoutForTesting(base::TimeDelta timeout); + private: // Holds information about (un)install operations. struct InstallInfo { @@ -71,6 +74,8 @@ std::unique_ptr<Installation> in_progress_installation_; std::unique_ptr<Uninstallation> in_progress_uninstallation_; + base::TimeDelta main_app_timeout_; + base::WeakPtrFactory<BorealisInstallerImpl> weak_ptr_factory_; };
diff --git a/chrome/browser/ash/borealis/borealis_installer_unittest.cc b/chrome/browser/ash/borealis/borealis_installer_unittest.cc index aec7c8e..57d8806 100644 --- a/chrome/browser/ash/borealis/borealis_installer_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_installer_unittest.cc
@@ -2,30 +2,39 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h" #include "chrome/browser/ash/borealis/borealis_installer_impl.h" #include <memory> +#include "base/base64.h" #include "base/callback_helpers.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/ash/borealis/borealis_context.h" #include "chrome/browser/ash/borealis/borealis_context_manager.h" #include "chrome/browser/ash/borealis/borealis_context_manager_mock.h" +#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h" #include "chrome/browser/ash/borealis/borealis_features.h" #include "chrome/browser/ash/borealis/borealis_metrics.h" #include "chrome/browser/ash/borealis/borealis_prefs.h" #include "chrome/browser/ash/borealis/borealis_service.h" #include "chrome/browser/ash/borealis/borealis_service_fake.h" #include "chrome/browser/ash/borealis/borealis_util.h" +#include "chrome/browser/ash/borealis/borealis_window_manager.h" +#include "chrome/browser/ash/borealis/infra/described.h" #include "chrome/browser/ash/borealis/testing/callback_factory.h" #include "chrome/browser/ash/guest_os/guest_os_registry_service.h" #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/dbus/cicerone/cicerone_client.h" +#include "chromeos/dbus/cicerone/fake_cicerone_client.h" #include "chromeos/dbus/concierge/concierge_client.h" #include "chromeos/dbus/concierge/fake_concierge_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dlcservice/fake_dlcservice_client.h" +#include "chromeos/dbus/seneschal/seneschal_client.h" #include "chromeos/dbus/vm_applications/apps.pb.h" #include "components/prefs/pref_service.h" #include "content/public/browser/network_service_instance.h" @@ -39,7 +48,7 @@ using ::testing::_; using ::testing::Mock; -using ::testing::StrictMock; +using ::testing::NiceMock; using InstallingState = BorealisInstaller::InstallingState; using BorealisInstallResult = BorealisInstallResult; @@ -56,19 +65,40 @@ BorealisInstallerTest() = default; ~BorealisInstallerTest() override = default; + // Disallow copy and assign. + BorealisInstallerTest(const BorealisInstallerTest&) = delete; + BorealisInstallerTest& operator=(const BorealisInstallerTest&) = delete; + protected: void SetUp() override { chromeos::DBusThreadManager::Initialize(); - chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr); + chromeos::CiceroneClient::InitializeFake(); + chromeos::ConciergeClient::InitializeFake( + static_cast<chromeos::FakeCiceroneClient*>( + chromeos::CiceroneClient::Get())); + chromeos::DlcserviceClient::InitializeFake(); + chromeos::SeneschalClient::InitializeFake(); histogram_tester_ = std::make_unique<base::HistogramTester>(); CreateProfile(); + test_features_ = std::make_unique<BorealisFeatures>(profile_.get()); + test_context_manager_ = + std::make_unique<NiceMock<BorealisContextManagerMock>>(); + test_window_manager_ = + std::make_unique<BorealisWindowManager>(profile_.get()); + test_disk_dispatcher_ = std::make_unique<BorealisDiskManagerDispatcher>(); + fake_service_ = BorealisServiceFake::UseFakeForTesting(profile_.get()); + fake_service_->SetFeaturesForTesting(test_features_.get()); + fake_service_->SetContextManagerForTesting(test_context_manager_.get()); + fake_service_->SetWindowManagerForTesting(test_window_manager_.get()); + fake_service_->SetDiskManagerDispatcherForTesting( + test_disk_dispatcher_.get()); + installer_impl_ = std::make_unique<BorealisInstallerImpl>(profile_.get()); installer_ = installer_impl_.get(); - observer_ = std::make_unique<StrictMock<MockObserver>>(); + observer_ = std::make_unique<NiceMock<MockObserver>>(); installer_->AddObserver(observer_.get()); - chromeos::DlcserviceClient::InitializeFake(); fake_dlcservice_client_ = static_cast<chromeos::FakeDlcserviceClient*>( chromeos::DlcserviceClient::Get()); UpdateCurrentDlcs(); @@ -78,28 +108,15 @@ } void TearDown() override { + ctx_.reset(); observer_.reset(); profile_.reset(); histogram_tester_.reset(); + chromeos::SeneschalClient::Shutdown(); + chromeos::DlcserviceClient::Shutdown(); chromeos::ConciergeClient::Shutdown(); chromeos::DBusThreadManager::Shutdown(); - chromeos::DlcserviceClient::Shutdown(); - } - - // Set expectations for observer events up to and including |end_state|. - void ExpectObserverEventsUntil(InstallingState end_state) { - InstallingState states[] = { - InstallingState::kInstallingDlc, - }; - - for (InstallingState state : states) { - EXPECT_CALL(*observer_, OnStateUpdated(state)); - if (state == end_state) - return; - } - - NOTREACHED(); } void StartAndRunToCompletion() { @@ -107,6 +124,41 @@ task_environment_.RunUntilIdle(); } + void CreateFakeMainApp() { + std::string desktop_file_id; + ASSERT_TRUE(base::Base64Decode("c3RlYW0=", &desktop_file_id)); + vm_tools::apps::ApplicationList list; + list.set_vm_name(ctx_->vm_name()); + list.set_container_name(ctx_->container_name()); + list.set_vm_type(vm_tools::apps::ApplicationList_VmType_BOREALIS); + vm_tools::apps::App* app = list.add_apps(); + app->set_desktop_file_id(desktop_file_id); + vm_tools::apps::App::LocaleString::Entry* entry = + app->mutable_name()->add_values(); + entry->set_locale(std::string()); + entry->set_value(desktop_file_id); + app->set_no_display(false); + guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile_.get()) + ->UpdateApplicationList(list); + } + + void PrepareSuccessfulInstallation() { + feature_list_.InitAndEnableFeature(features::kBorealis); + fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + ctx_ = BorealisContext::CreateBorealisContextForTesting(profile_.get()); + ctx_->set_vm_name("borealis"); + ctx_->set_container_name("penguin"); + EXPECT_CALL(*test_context_manager_, StartBorealis) + .WillOnce(testing::Invoke( + [this](BorealisContextManager::ResultCallback callback) { + std::move(callback).Run( + BorealisContextManager::ContextOrFailure(ctx_.get())); + // Make a fake main app. We do this inside the callback as it is a + // better way to simulate garcon's callback. + CreateFakeMainApp(); + })); + } + void UpdateCurrentDlcs() { base::RunLoop run_loop; fake_dlcservice_client_->GetExistingDlcs(base::BindOnce( @@ -122,6 +174,12 @@ content::BrowserTaskEnvironment task_environment_; std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<BorealisContext> ctx_; + std::unique_ptr<BorealisFeatures> test_features_; + std::unique_ptr<BorealisContextManagerMock> test_context_manager_; + std::unique_ptr<BorealisWindowManager> test_window_manager_; + std::unique_ptr<BorealisDiskManagerDispatcher> test_disk_dispatcher_; + BorealisServiceFake* fake_service_; std::unique_ptr<base::HistogramTester> histogram_tester_; std::unique_ptr<BorealisInstallerImpl> installer_impl_; BorealisInstaller* installer_; @@ -138,10 +196,6 @@ profile_builder.SetProfileName("defaultprofile"); profile_ = profile_builder.Build(); } - - // Disallow copy and assign. - BorealisInstallerTest(const BorealisInstallerTest&) = delete; - BorealisInstallerTest& operator=(const BorealisInstallerTest&) = delete; }; class BorealisInstallerTestDlc @@ -180,12 +234,9 @@ } TEST_F(BorealisInstallerTest, SucessfulInstallation) { - feature_list_.InitAndEnableFeature(features::kBorealis); - fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + PrepareSuccessfulInstallation(); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kSuccess)); - StartAndRunToCompletion(); UpdateCurrentDlcs(); @@ -195,11 +246,33 @@ BorealisService::GetForProfile(profile_.get())->Features().IsEnabled()); } +TEST_F(BorealisInstallerTest, HandlesMainAppPreExisting) { + PrepareSuccessfulInstallation(); + + // Normally we add the main app after signaling completion, which this a + // better way of modeling how garcon works. In this test we add the main app + // well before, to simulate when garcon actually wins the race. + CreateFakeMainApp(); + + EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kSuccess)); + StartAndRunToCompletion(); +} + +TEST_F(BorealisInstallerTest, InstallationHasAllStages) { + PrepareSuccessfulInstallation(); + + EXPECT_CALL(*observer_, OnStateUpdated(InstallingState::kInstallingDlc)); + EXPECT_CALL(*observer_, OnStateUpdated(InstallingState::kStartingUp)); + EXPECT_CALL(*observer_, + OnStateUpdated(InstallingState::kAwaitingApplications)); + + StartAndRunToCompletion(); +} + TEST_F(BorealisInstallerTest, CancelledInstallation) { feature_list_.InitAndEnableFeature(features::kBorealis); fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL(*observer_, OnCancelInitiated()); EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kCancelled)); @@ -216,10 +289,8 @@ } TEST_F(BorealisInstallerTest, InstallationInProgess) { - feature_list_.InitAndEnableFeature(features::kBorealis); - fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + PrepareSuccessfulInstallation(); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL( *observer_, OnInstallationEnded(BorealisInstallResult::kBorealisInstallInProgress)); @@ -237,8 +308,7 @@ } TEST_F(BorealisInstallerTest, CancelledThenSuccessfulInstallation) { - feature_list_.InitAndEnableFeature(features::kBorealis); - fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + PrepareSuccessfulInstallation(); EXPECT_CALL(*observer_, OnCancelInitiated()); @@ -250,7 +320,6 @@ EXPECT_FALSE( BorealisService::GetForProfile(profile_.get())->Features().IsEnabled()); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kSuccess)); installer_->Start(); @@ -264,10 +333,8 @@ } TEST_F(BorealisInstallerTest, SucessfulInstallationRecordMetrics) { - feature_list_.InitAndEnableFeature(features::kBorealis); - fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + PrepareSuccessfulInstallation(); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kSuccess)); StartAndRunToCompletion(); @@ -282,7 +349,6 @@ // This error is arbitrarily chosen for simplicity. fake_dlcservice_client_->set_install_error(dlcservice::kErrorInternal); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); EXPECT_CALL(*observer_, OnInstallationEnded(BorealisInstallResult::kDlcInternalError)); StartAndRunToCompletion(); @@ -294,6 +360,46 @@ histogram_tester_->ExpectTotalCount(kBorealisInstallOverallTimeHistogram, 0); } +TEST_F(BorealisInstallerTest, ReportsStartupFailureAsError) { + feature_list_.InitAndEnableFeature(features::kBorealis); + fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + EXPECT_CALL(*test_context_manager_, StartBorealis) + .WillOnce( + testing::Invoke([](BorealisContextManager::ResultCallback callback) { + std::move(callback).Run( + BorealisContextManager::ContextOrFailure::Unexpected( + Described<BorealisStartupResult>{ + BorealisStartupResult::kStartVmFailed, "Some Error"})); + })); + + EXPECT_CALL(*observer_, OnStateUpdated(InstallingState::kInstallingDlc)); + EXPECT_CALL(*observer_, OnStateUpdated(InstallingState::kStartingUp)); + EXPECT_CALL(*observer_, + OnInstallationEnded(BorealisInstallResult::kStartupFailed)); + + StartAndRunToCompletion(); +} + +TEST_F(BorealisInstallerTest, ReportsMainAppMissingAsError) { + feature_list_.InitAndEnableFeature(features::kBorealis); + fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); + ctx_ = BorealisContext::CreateBorealisContextForTesting(profile_.get()); + EXPECT_CALL(*test_context_manager_, StartBorealis) + .WillOnce(testing::Invoke( + [this](BorealisContextManager::ResultCallback callback) { + std::move(callback).Run( + BorealisContextManager::ContextOrFailure(ctx_.get())); + })); + + // Set a zero timeout otherwise the in-progress timeout gets cleaned up. + installer_impl_->SetMainAppTimeoutForTesting(base::TimeDelta::FromSeconds(0)); + + EXPECT_CALL(*observer_, + OnInstallationEnded(BorealisInstallResult::kMainAppNotPresent)); + + StartAndRunToCompletion(); +} + // Note that we don't check if the DLC has/hasn't been installed, since the // mocked DLC service will always succeed, so we only care about how the error // code returned by the service is handled by the installer. @@ -301,7 +407,7 @@ feature_list_.InitAndEnableFeature(features::kBorealis); fake_dlcservice_client_->set_install_error(GetParam().first); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); + EXPECT_CALL(*observer_, OnStateUpdated(InstallingState::kInstallingDlc)); EXPECT_CALL(*observer_, OnInstallationEnded(GetParam().second)); StartAndRunToCompletion(); @@ -337,13 +443,8 @@ void SetUp() override { BorealisInstallerTest::SetUp(); // Install borealis. - feature_list_.InitAndEnableFeature(features::kBorealis); - fake_dlcservice_client_->set_install_error(dlcservice::kErrorNone); - ExpectObserverEventsUntil(InstallingState::kInstallingDlc); - EXPECT_CALL(*observer_, - OnInstallationEnded(BorealisInstallResult::kSuccess)); - installer_->Start(); - task_environment_.RunUntilIdle(); + PrepareSuccessfulInstallation(); + StartAndRunToCompletion(); ASSERT_TRUE( BorealisService::GetForProfile(profile_.get())->Features().IsEnabled()); } @@ -388,10 +489,7 @@ CallbackFactory callback_factory; EXPECT_CALL(callback_factory, Call(BorealisUninstallResult::kShutdownFailed)); - testing::StrictMock<BorealisContextManagerMock> mock_manager; - BorealisServiceFake::UseFakeForTesting(profile_.get()) - ->SetContextManagerForTesting(&mock_manager); - EXPECT_CALL(mock_manager, ShutDownBorealis(testing::_)) + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) .WillOnce(testing::Invoke( [](base::OnceCallback<void(BorealisShutdownResult)> callback) { std::move(callback).Run(BorealisShutdownResult::kFailed); @@ -415,6 +513,11 @@ EXPECT_CALL(callback_factory, Call(BorealisUninstallResult::kRemoveDiskFailed)); + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); chromeos::FakeConciergeClient* fake_concierge_client = chromeos::FakeConciergeClient::Get(); fake_concierge_client->set_destroy_disk_image_response(absl::nullopt); @@ -436,6 +539,11 @@ EXPECT_CALL(callback_factory, Call(BorealisUninstallResult::kRemoveDlcFailed)); + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); fake_dlcservice_client_->set_uninstall_error("some failure"); installer_->Uninstall(callback_factory.BindOnce()); @@ -459,6 +567,11 @@ .size(), 1); + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); installer_->Uninstall(callback_factory.BindOnce()); task_environment_.RunUntilIdle(); @@ -493,14 +606,29 @@ EXPECT_CALL(callback_factory, Call(BorealisUninstallResult::kSuccess)) .Times(2); + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); installer_->Uninstall(callback_factory.BindOnce()); task_environment_.RunUntilIdle(); + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); installer_->Uninstall(callback_factory.BindOnce()); task_environment_.RunUntilIdle(); } TEST_F(BorealisUninstallerTest, SuccessfulUninstallationRecordsMetrics) { + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kSuccess); + })); installer_->Uninstall(base::DoNothing()); task_environment_.RunUntilIdle(); @@ -511,8 +639,12 @@ } TEST_F(BorealisUninstallerTest, FailedUninstallationRecordsMetrics) { - // Arbitrarily choose to fail via DLC removal. - fake_dlcservice_client_->set_uninstall_error("some failure"); + // Fail via shutdown, as that is the first step. + EXPECT_CALL(*test_context_manager_, ShutDownBorealis(testing::_)) + .WillOnce(testing::Invoke( + [](base::OnceCallback<void(BorealisShutdownResult)> callback) { + std::move(callback).Run(BorealisShutdownResult::kFailed); + })); installer_->Uninstall(base::DoNothing()); task_environment_.RunUntilIdle(); @@ -521,7 +653,7 @@ 1); histogram_tester_->ExpectUniqueSample( kBorealisUninstallResultHistogram, - BorealisUninstallResult::kRemoveDlcFailed, 1); + BorealisUninstallResult::kShutdownFailed, 1); } } // namespace
diff --git a/chrome/browser/ash/borealis/borealis_metrics.h b/chrome/browser/ash/borealis/borealis_metrics.h index 0cb6cdf..f28861c 100644 --- a/chrome/browser/ash/borealis/borealis_metrics.h +++ b/chrome/browser/ash/borealis/borealis_metrics.h
@@ -36,7 +36,9 @@ kDlcUnknownError = 9, kOffline = 10, kDlcNeedUpdateError = 11, - kMaxValue = kDlcNeedUpdateError, + kStartupFailed = 12, + kMainAppNotPresent = 13, + kMaxValue = kMainAppNotPresent, }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/chrome/browser/ash/child_accounts/child_user_service.cc b/chrome/browser/ash/child_accounts/child_user_service.cc index b6809b4..733c2dd 100644 --- a/chrome/browser/ash/child_accounts/child_user_service.cc +++ b/chrome/browser/ash/child_accounts/child_user_service.cc
@@ -4,18 +4,58 @@ #include "chrome/browser/ash/child_accounts/child_user_service.h" +#include "base/bind.h" +#include "base/check.h" +#include "base/metrics/histogram_functions.h" #include "base/time/time.h" +#include "base/values.h" #include "chrome/browser/ash/child_accounts/time_limits/app_activity_registry.h" #include "chrome/browser/ash/child_accounts/time_limits/app_time_controller.h" #include "chrome/browser/ash/child_accounts/time_limits/app_types.h" #include "chrome/browser/ash/child_accounts/time_limits/web_time_limit_enforcer.h" +#include "chrome/browser/ash/child_accounts/usage_time_limit_processor.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/browser_context.h" #include "extensions/common/constants.h" #include "url/gurl.h" namespace ash { +namespace { +// UMA histogram FamilyUser.TimeLimitPolicyTypes +// Reports TimeLimitPolicyType which indicates what time limit policies +// are enabled for current Family Link user. Could report multiple buckets if +// multiple policies are enabled. +constexpr char kTimeLimitPolicyTypesHistogramName[] = + "FamilyUser.TimeLimitPolicyTypes"; + +ChildUserService::TimeLimitPolicyType GetTimeLimitPolicyType( + usage_time_limit::PolicyType policy_type) { + ChildUserService::TimeLimitPolicyType time_limit_policy; + switch (policy_type) { + case usage_time_limit::PolicyType::kFixedLimit: + time_limit_policy = ChildUserService::TimeLimitPolicyType::kBedTimeLimit; + break; + case usage_time_limit::PolicyType::kUsageLimit: + time_limit_policy = + ChildUserService::TimeLimitPolicyType::kScreenTimeLimit; + break; + case usage_time_limit::PolicyType::kOverride: + time_limit_policy = + ChildUserService::TimeLimitPolicyType::kOverrideTimeLimit; + break; + case usage_time_limit::PolicyType::kNoPolicy: + time_limit_policy = ChildUserService::TimeLimitPolicyType::kNoTimeLimit; + break; + default: + NOTREACHED(); + } + return time_limit_policy; +} +} // namespace + // static const char ChildUserService::kFamilyLinkHelperAppPackageName[] = "com.google.android.apps.kids.familylinkhelper"; @@ -39,10 +79,23 @@ : nullptr; } -ChildUserService::ChildUserService(content::BrowserContext* context) { - DCHECK(context); +// static +const char* ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest() { + return kTimeLimitPolicyTypesHistogramName; +} + +ChildUserService::ChildUserService(content::BrowserContext* context) + : profile_(Profile::FromBrowserContext(context)) { + DCHECK(profile_); app_time_controller_ = std::make_unique<app_time::AppTimeController>( - Profile::FromBrowserContext(context)); + profile_, base::BindRepeating(&ChildUserService::ReportTimeLimitPolicy, + base::Unretained(this))); + + pref_change_registrar_.Init(profile_->GetPrefs()); + pref_change_registrar_.Add( + prefs::kUsageTimeLimit, + base::BindRepeating(&ChildUserService::ReportTimeLimitPolicy, + base::Unretained(this))); } ChildUserService::~ChildUserService() = default; @@ -132,20 +185,48 @@ return app_time_controller_->web_time_enforcer()->time_limit(); } -void ChildUserService::GetEnabledAppTimeLimitPolicies( - std::set<FamilyUserParentalControlMetrics::TimeLimitPolicyType>* - enabled_policies) { - if (!app_time_controller_ || !enabled_policies) - return; +void ChildUserService ::ReportTimeLimitPolicy() const { + const base::DictionaryValue* time_limit_prefs = + profile_->GetPrefs()->GetDictionary(prefs::kUsageTimeLimit); + DCHECK(time_limit_prefs); - if (app_time_controller_->HasWebTimeLimitRestriction()) { - enabled_policies->insert( - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kWebTimeLimit); + std::set<usage_time_limit::PolicyType> enabled_policies = + usage_time_limit::GetEnabledTimeLimitPolicies(*time_limit_prefs); + + for (const auto& policy_type : enabled_policies) { + TimeLimitPolicyType time_limit_policy = GetTimeLimitPolicyType(policy_type); + + // `enabled_policies` does not contains + // usage_time_limit::PolicyType::kNoPolicy, so `time_limit_policy` never + // equals to TimeLimitPolicyType::kNoTimeLimit. + if (time_limit_policy == TimeLimitPolicyType::kNoTimeLimit) + continue; + + base::UmaHistogramEnumeration( + /*name=*/kTimeLimitPolicyTypesHistogramName, + /*sample=*/time_limit_policy); } + bool has_policy_enabled = !enabled_policies.empty(); + if (app_time_controller_->HasAppTimeLimitRestriction()) { - enabled_policies->insert( - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kAppTimeLimit); + base::UmaHistogramEnumeration( + /*name=*/kTimeLimitPolicyTypesHistogramName, + /*sample=*/TimeLimitPolicyType::kAppTimeLimit); + has_policy_enabled = true; + } + + if (app_time_controller_->HasWebTimeLimitRestriction()) { + base::UmaHistogramEnumeration( + /*name=*/kTimeLimitPolicyTypesHistogramName, + /*sample=*/TimeLimitPolicyType::kWebTimeLimit); + has_policy_enabled = true; + } + + if (!has_policy_enabled) { + base::UmaHistogramEnumeration( + /*name=*/kTimeLimitPolicyTypesHistogramName, + /*sample=*/TimeLimitPolicyType::kNoTimeLimit); } } @@ -155,6 +236,7 @@ app_time_controller_->RecordMetricsOnShutdown(); app_time_controller_.reset(); } + pref_change_registrar_.Remove(prefs::kUsageTimeLimit); } } // namespace ash
diff --git a/chrome/browser/ash/child_accounts/child_user_service.h b/chrome/browser/ash/child_accounts/child_user_service.h index 308ea52..8481cc3 100644 --- a/chrome/browser/ash/child_accounts/child_user_service.h +++ b/chrome/browser/ash/child_accounts/child_user_service.h
@@ -9,10 +9,10 @@ #include <set> #include <string> -#include "chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h" #include "chrome/browser/ash/child_accounts/time_limits/app_activity_report_interface.h" #include "chrome/browser/ash/child_accounts/time_limits/app_time_limit_interface.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/prefs/pref_change_registrar.h" namespace base { class TimeDelta; @@ -27,6 +27,7 @@ } // namespace enterprise_management class GURL; +class Profile; namespace ash { namespace app_time { @@ -55,11 +56,32 @@ ChildUserService* const service_; }; + // These enum values represent the current Family Link user's time limit + // policy type for the Family Experiences team's metrics. Multiple time + // limit policy types might be enabled at the same time. These values are + // logged to UMA. Entries should not be renumbered and numeric values should + // never be reused. Please keep in sync with "TimeLimitPolicyType" in + // src/tools/metrics/histograms/enums.xml. + enum class TimeLimitPolicyType { + kNoTimeLimit = 0, + kOverrideTimeLimit = 1, + kBedTimeLimit = 2, + kScreenTimeLimit = 3, + kWebTimeLimit = 4, + kAppTimeLimit = 5, // Does not cover blocked apps. + + // Used for UMA. Update kMaxValue to the last value. Add future entries + // above this comment. Sync with enums.xml. + kMaxValue = kAppTimeLimit + }; + // Family Link helper(for child and teens) is an app available to supervised // users and the companion app of Family Link app(for parents). static const char kFamilyLinkHelperAppPackageName[]; static const char kFamilyLinkHelperAppPlayStoreURL[]; + static const char* GetTimeLimitPolicyTypesHistogramNameForTest(); + explicit ChildUserService(content::BrowserContext* context); ChildUserService(const ChildUserService&) = delete; ChildUserService& operator=(const ChildUserService&) = delete; @@ -96,17 +118,19 @@ // |features::kWebTimeLimits| features are enabled. base::TimeDelta GetWebTimeLimit() const; - // Checks whether app time limit and chrome app time limit are enabled and - // inserts the enabled types to `enabled_policies`. - void GetEnabledAppTimeLimitPolicies( - std::set<FamilyUserParentalControlMetrics::TimeLimitPolicyType>* - enabled_policies); + // Report enabled TimeLimitPolicyType. + void ReportTimeLimitPolicy() const; private: // KeyedService: void Shutdown() override; std::unique_ptr<app_time::AppTimeController> app_time_controller_; + + // Preference changes observer. + PrefChangeRegistrar pref_change_registrar_; + + Profile* const profile_; }; } // namespace ash
diff --git a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.cc b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.cc index e4b8c67..70d4553 100644 --- a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.cc +++ b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.cc
@@ -4,45 +4,16 @@ #include "chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h" -#include <set> - #include "base/check.h" -#include "base/metrics/histogram_functions.h" -#include "base/values.h" #include "chrome/browser/ash/child_accounts/child_user_service.h" #include "chrome/browser/ash/child_accounts/child_user_service_factory.h" -#include "chrome/browser/ash/child_accounts/usage_time_limit_processor.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" -#include "chrome/browser/supervised_user/supervised_user_url_filter.h" -#include "chrome/common/pref_names.h" -#include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" namespace ash { -namespace { - -// UMA histogram FamilyUser.TimeLimitPolicyTypes -// Reports TimeLimitPolicyType which indicates what time limit policies -// are enabled for current Family Link user. Could report multiple buckets if -// multiple policies are enabled. -constexpr char kTimeLimitPolicyTypesHistogramName[] = - "FamilyUser.TimeLimitPolicyTypes"; - -// UMA histogram FamilyUser.WebFilterType -// Reports WebFilterType which indicates web filter behaviour are used for -// current Family Link user. -constexpr char kWebFilterTypeHistogramName[] = "FamilyUser.WebFilterType"; - -// UMA histogram FamilyUser.ManualSiteListType -// Reports ManualSiteListType which indicates approved list and blocked list -// usage for current Family Link user. -constexpr char kManagedSiteListHistogramName[] = "FamilyUser.ManagedSiteList"; - -} // namespace - FamilyUserParentalControlMetrics::FamilyUserParentalControlMetrics( Profile* profile) : profile_(profile), @@ -54,79 +25,25 @@ FamilyUserParentalControlMetrics::~FamilyUserParentalControlMetrics() = default; -// static -const char* FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest() { - return kTimeLimitPolicyTypesHistogramName; -} - -// static -const char* -FamilyUserParentalControlMetrics::GetWebFilterTypeHistogramNameForTest() { - return kWebFilterTypeHistogramName; -} - -// static -const char* -FamilyUserParentalControlMetrics::GetManagedSiteListHistogramNameForTest() { - return kManagedSiteListHistogramName; -} - -void FamilyUserParentalControlMetrics::ReportTimeLimitPolicy() const { - const base::DictionaryValue* time_limit_prefs = - profile_->GetPrefs()->GetDictionary(prefs::kUsageTimeLimit); - DCHECK(time_limit_prefs); - - std::set<TimeLimitPolicyType> enabled_policies; - usage_time_limit::GetEnabledTimeLimitPolicies(&enabled_policies, - *time_limit_prefs); - ChildUserService* child_user_service = - ChildUserServiceFactory::GetForBrowserContext(profile_); - if (child_user_service) - child_user_service->GetEnabledAppTimeLimitPolicies(&enabled_policies); - - if (enabled_policies.empty()) { - base::UmaHistogramEnumeration( - /*name=*/kTimeLimitPolicyTypesHistogramName, - /*sample=*/TimeLimitPolicyType::kNoTimeLimit); - return; - } - - for (const TimeLimitPolicyType& policy : enabled_policies) { - base::UmaHistogramEnumeration( - /*name=*/kTimeLimitPolicyTypesHistogramName, - /*sample=*/policy); - } -} -void FamilyUserParentalControlMetrics::ReportWebFilterPolicy() const { - // Ignores reports when prefs::kDefaultSupervisedUserFilteringBehavior is - // reset to default value. It might happen during sign out. - SupervisedUserService* supervised_user_service = - SupervisedUserServiceFactory::GetForProfile(profile_); - if (supervised_user_service->IsFilteringBehaviorPrefDefault() || - !supervised_user_service->GetURLFilter()) { - return; - } - - base::UmaHistogramEnumeration( - kWebFilterTypeHistogramName, - supervised_user_service->GetURLFilter()->GetWebFilterType()); - base::UmaHistogramEnumeration( - kManagedSiteListHistogramName, - supervised_user_service->GetURLFilter()->GetManagedSiteList()); -} - void FamilyUserParentalControlMetrics::OnNewDay() { // Reports Family Link user time limit policy type. - ReportTimeLimitPolicy(); + ChildUserService* child_user_service = + ChildUserServiceFactory::GetForBrowserContext(profile_); + DCHECK(child_user_service); + child_user_service->ReportTimeLimitPolicy(); - // Ignores the first report during OOBE. Prefs related to web filter policy - // may not have been successfully sync during OOBE process, which introduces - // bias. + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + DCHECK(supervised_user_service); + // Ignores the first report during OOBE. Prefs related to web filter + // policy may not have been successfully sync during OOBE process, which + // introduces bias. if (first_report_on_current_device_) { first_report_on_current_device_ = false; } else { - ReportWebFilterPolicy(); + // Ignores reports when web filter prefs are reset to default value. It + // might happen during sign out. + supervised_user_service->ReportNonDefaultWebFilterValue(); } }
diff --git a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h index fb760334..f86846e 100644 --- a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h +++ b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h
@@ -12,30 +12,10 @@ namespace ash { // A class for recording time limit metrics and web filter metrics for Family -// Link users on Chrome OS. These metrics will be recorded at the beginning of -// the first active session daily. +// Link users on Chrome OS at the beginning of the first active session daily. class FamilyUserParentalControlMetrics : public FamilyUserMetricsService::Observer { public: - // These enum values represent the current Family Link user's time limit - // policy type for the Family Experiences team's metrics. Multiple time limit - // policy types might be enabled at the same time. These values are - // logged to UMA. Entries should not be renumbered and numeric values should - // never be reused. Please keep in sync with "TimeLimitPolicyType" in - // src/tools/metrics/histograms/enums.xml. - enum class TimeLimitPolicyType { - kNoTimeLimit = 0, - kOverrideTimeLimit = 1, - kBedTimeLimit = 2, - kScreenTimeLimit = 3, - kWebTimeLimit = 4, - kAppTimeLimit = 5, - - // Used for UMA. Update kMaxValue to the last value. Add future entries - // above this comment. Sync with enums.xml. - kMaxValue = kAppTimeLimit - }; - explicit FamilyUserParentalControlMetrics(Profile* profile); FamilyUserParentalControlMetrics(const FamilyUserParentalControlMetrics&) = delete; @@ -43,20 +23,10 @@ const FamilyUserParentalControlMetrics&) = delete; ~FamilyUserParentalControlMetrics() override; - static const char* GetTimeLimitPolicyTypesHistogramNameForTest(); - static const char* GetWebFilterTypeHistogramNameForTest(); - static const char* GetManagedSiteListHistogramNameForTest(); - - // TODO(crbug/1152622): listen to the policy by using PrefChangeRegistrar to - // observe pref. Report when policy change in addition to OnNewDay(). // FamilyUserMetricsService::Observer: void OnNewDay() override; private: - void ReportTimeLimitPolicy() const; - void ReportWebFilterPolicy() const; - - private: Profile* const profile_; bool first_report_on_current_device_ = false; };
diff --git a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc index cf14763..7ba2e0b 100644 --- a/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc +++ b/chrome/browser/ash/child_accounts/family_user_parental_control_metrics_unittest.cc
@@ -101,11 +101,11 @@ profile_builder.SetSupervisedUserId(supervised_users::kChildAccountSUID); profile_ = profile_builder.Build(); EXPECT_TRUE(profile_->IsChild()); - parental_control_metrics_ = - std::make_unique<FamilyUserParentalControlMetrics>(profile_.get()); supervised_user_service_ = SupervisedUserServiceFactory::GetForProfile(profile_.get()); supervised_user_service_->Init(); + parental_control_metrics_ = + std::make_unique<FamilyUserParentalControlMetrics>(profile_.get()); } void TearDown() override { @@ -118,7 +118,7 @@ ChildUserService* service = ChildUserServiceFactory::GetForBrowserContext(profile_.get()); ChildUserService::TestApi test_api = ChildUserService::TestApi(service); - DCHECK(test_api.app_time_controller()); + EXPECT_TRUE(test_api.app_time_controller()); return test_api.app_time_controller()->app_registry(); } @@ -130,6 +130,8 @@ content::BrowserTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + base::HistogramTester histogram_tester_; + private: base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<FamilyUserParentalControlMetrics> parental_control_metrics_; @@ -137,7 +139,7 @@ }; TEST_F(FamilyUserParentalControlMetricsTest, BedAndScreenTimeLimitMetrics) { - base::HistogramTester histogram_tester; + ASSERT_TRUE(ChildUserServiceFactory::GetForBrowserContext(profile_.get())); base::Value policy_content = utils::CreateTimeLimitPolicy(utils::CreateTime(6, 0)); @@ -155,30 +157,43 @@ /*last_updated=*/base::Time::Now()); GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); - // Triggers report: + + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kBedTimeLimit, + /*expected_count=*/1); + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kScreenTimeLimit, + /*expected_count=*/1); + + histogram_tester_.ExpectTotalCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*expected_count=*/2); + + // Tests daily report. OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kBedTimeLimit, - /*expected_count=*/1); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), - /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kScreenTimeLimit, - /*expected_count=*/1); - - histogram_tester.ExpectTotalCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + ChildUserService::TimeLimitPolicyType::kBedTimeLimit, /*expected_count=*/2); + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kScreenTimeLimit, + /*expected_count=*/2); + + histogram_tester_.ExpectTotalCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*expected_count=*/4); } TEST_F(FamilyUserParentalControlMetricsTest, OverrideTimeLimitMetrics) { - base::HistogramTester histogram_tester; + ASSERT_TRUE(ChildUserServiceFactory::GetForBrowserContext(profile_.get())); // Adds override time policy created at 1 day ago. base::Value policy_content = @@ -191,22 +206,17 @@ /*duration=*/base::TimeDelta::FromHours(2)); GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); - // Triggers report. - OnNewDay(); - // The override time limit policy would not get reported since the difference // between reported and created time are greater than 1 day. - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kOverrideTimeLimit, + ChildUserService::TimeLimitPolicyType::kOverrideTimeLimit, /*expected_count=*/0); - histogram_tester.ExpectUniqueSample( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + histogram_tester_.ExpectUniqueSample( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kNoTimeLimit, + ChildUserService::TimeLimitPolicyType::kNoTimeLimit, /*expected_count=*/1); // Adds override time policy. Created and reported within 1 day. @@ -217,26 +227,28 @@ /*duration=*/base::TimeDelta::FromHours(2)); GetPrefs()->Set(prefs::kUsageTimeLimit, policy_content); - // Triggers report. - OnNewDay(); - // The override time limit policy would get reported since the created // time and reported time are within 1 day. - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kOverrideTimeLimit, + ChildUserService::TimeLimitPolicyType::kOverrideTimeLimit, /*expected_count=*/1); - histogram_tester.ExpectTotalCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + // Tests daily report. + OnNewDay(); + + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kOverrideTimeLimit, /*expected_count=*/2); + histogram_tester_.ExpectTotalCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*expected_count=*/3); } TEST_F(FamilyUserParentalControlMetricsTest, AppAndWebTimeLimitMetrics) { - base::HistogramTester histogram_tester; apps::AppServiceTest app_service_test_; ArcAppTest arc_test_; @@ -274,45 +286,59 @@ *value = builder.value().Clone(); } + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kWebTimeLimit, + /*expected_count=*/1); + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kAppTimeLimit, + /*expected_count=*/1); + + // Tests daily report. OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kWebTimeLimit, - /*expected_count=*/1); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), - /*sample=*/ - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kAppTimeLimit, - /*expected_count=*/1); - histogram_tester.ExpectTotalCount( - FamilyUserParentalControlMetrics:: - GetTimeLimitPolicyTypesHistogramNameForTest(), + ChildUserService::TimeLimitPolicyType::kWebTimeLimit, /*expected_count=*/2); + histogram_tester_.ExpectBucketCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*sample=*/ + ChildUserService::TimeLimitPolicyType::kAppTimeLimit, + /*expected_count=*/2); + + histogram_tester_.ExpectTotalCount( + ChildUserService::GetTimeLimitPolicyTypesHistogramNameForTest(), + /*expected_count=*/4); } TEST_F(FamilyUserParentalControlMetricsTest, WebFilterTypeMetric) { - base::HistogramTester histogram_tester; - + // Overriding the value of prefs::kSupervisedUserSafeSites and + // prefs::kDefaultSupervisedUserFilteringBehavior in default storage is + // needed, otherwise no report could be triggered policies change or + // OnNewDay(). Since the default values are the same of override values, the + // WebFilterType doesn't change and no report here. GetPrefs()->SetInteger(prefs::kDefaultSupervisedUserFilteringBehavior, SupervisedUserURLFilter::ALLOW); GetPrefs()->SetBoolean(prefs::kSupervisedUserSafeSites, true); + + // Tests daily report. OnNewDay(); - histogram_tester.ExpectUniqueSample( - FamilyUserParentalControlMetrics::FamilyUserParentalControlMetrics:: - GetWebFilterTypeHistogramNameForTest(), + histogram_tester_.ExpectUniqueSample( + SupervisedUserURLFilter::GetWebFilterTypeHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::WebFilterType::kTryToBlockMatureSites, /*expected_count=*/1); // Tests filter "allow all sites". GetPrefs()->SetBoolean(prefs::kSupervisedUserSafeSites, false); - OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics::GetWebFilterTypeHistogramNameForTest(), + + histogram_tester_.ExpectBucketCount( + SupervisedUserURLFilter::GetWebFilterTypeHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::WebFilterType::kAllowAllSites, /*expected_count=*/1); @@ -320,30 +346,32 @@ // Tests filter "only allow certain sites" on Family Link app. GetPrefs()->SetInteger(prefs::kDefaultSupervisedUserFilteringBehavior, SupervisedUserURLFilter::BLOCK); - OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics::GetWebFilterTypeHistogramNameForTest(), + + histogram_tester_.ExpectBucketCount( + SupervisedUserURLFilter::GetWebFilterTypeHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::WebFilterType::kCertainSites, /*expected_count=*/1); - histogram_tester.ExpectTotalCount( - FamilyUserParentalControlMetrics::GetWebFilterTypeHistogramNameForTest(), + histogram_tester_.ExpectTotalCount( + SupervisedUserURLFilter::GetWebFilterTypeHistogramNameForTest(), /*expected_count=*/3); } TEST_F(FamilyUserParentalControlMetricsTest, ManagedSiteListTypeMetric) { - base::HistogramTester histogram_tester; - + // Overriding the value of prefs::kSupervisedUserSafeSites and + // prefs::kDefaultSupervisedUserFilteringBehavior in default storage is + // needed, otherwise no report could be triggered by policies change or + // OnNewDay(). Since the default values are the same of override values, the + // WebFilterType doesn't change and no report here. GetPrefs()->SetInteger(prefs::kDefaultSupervisedUserFilteringBehavior, SupervisedUserURLFilter::ALLOW); - GetPrefs()->Set(prefs::kSupervisedUserManualHosts, base::DictionaryValue()); - GetPrefs()->Set(prefs::kSupervisedUserManualURLs, base::DictionaryValue()); + GetPrefs()->SetBoolean(prefs::kSupervisedUserSafeSites, true); + // Tests daily report. OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetManagedSiteListHistogramNameForTest(), + histogram_tester_.ExpectUniqueSample( + SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::ManagedSiteList::kEmpty, /*expected_count=*/1); @@ -355,10 +383,9 @@ base::DictionaryValue* hosts = hosts_update.Get(); hosts->SetKey(kExampleHost0, base::Value(false)); } - OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetManagedSiteListHistogramNameForTest(), + + histogram_tester_.ExpectBucketCount( + SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::ManagedSiteList::kBlockedListOnly, /*expected_count=*/1); @@ -370,10 +397,9 @@ base::DictionaryValue* hosts = hosts_update.Get(); hosts->SetKey(kExampleHost0, base::Value(true)); } - OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetManagedSiteListHistogramNameForTest(), + + histogram_tester_.ExpectBucketCount( + SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::ManagedSiteList::kApprovedListOnly, /*expected_count=*/1); @@ -385,17 +411,15 @@ base::DictionaryValue* urls = urls_update.Get(); urls->SetKey(kExampleURL1, base::Value(false)); } - OnNewDay(); - histogram_tester.ExpectBucketCount( - FamilyUserParentalControlMetrics:: - GetManagedSiteListHistogramNameForTest(), + + histogram_tester_.ExpectBucketCount( + SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest(), /*sample=*/ SupervisedUserURLFilter::ManagedSiteList::kBoth, /*expected_count=*/1); - histogram_tester.ExpectTotalCount( - FamilyUserParentalControlMetrics:: - GetManagedSiteListHistogramNameForTest(), + histogram_tester_.ExpectTotalCount( + SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest(), /*expected_count=*/4); }
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc index 6f11804..7aa748e 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc
@@ -209,7 +209,9 @@ registry->RegisterDictionaryPref(prefs::kPerAppTimeLimitsAllowlistPolicy); } -AppTimeController::AppTimeController(Profile* profile) +AppTimeController::AppTimeController( + Profile* profile, + base::RepeatingClosure on_policy_updated_callback) : profile_(profile), app_service_wrapper_(std::make_unique<AppServiceWrapper>(profile)), app_registry_( @@ -218,7 +220,8 @@ profile->GetPrefs())), web_time_activity_provider_(std::make_unique<WebTimeActivityProvider>( this, - app_service_wrapper_.get())) { + app_service_wrapper_.get())), + on_policy_updated_callback_(on_policy_updated_callback) { DCHECK(profile); if (WebTimeLimitEnforcer::IsEnabled()) @@ -388,6 +391,8 @@ .size(); base::UmaHistogramCounts1000(kBlockedAppsCountMetric, blocked_apps); + + on_policy_updated_callback_.Run(); } }
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.h b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.h index fbd5406..b8fc174 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.h +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" @@ -70,7 +71,8 @@ // Registers preferences static void RegisterProfilePrefs(PrefRegistrySimple* registry); - explicit AppTimeController(Profile* profile); + AppTimeController(Profile* profile, + base::RepeatingClosure on_policy_updated_callback); AppTimeController(const AppTimeController&) = delete; AppTimeController& operator=(const AppTimeController&) = delete; ~AppTimeController() override; @@ -180,6 +182,8 @@ int patl_policy_update_count_ = 0; int apps_with_limit_ = 0; + base::RepeatingClosure on_policy_updated_callback_; + base::WeakPtrFactory<AppTimeController> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_controller_unittest.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_controller_unittest.cc index 9e492f9..c8cef63c6 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_time_controller_unittest.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_time_controller_unittest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ash/child_accounts/time_limits/app_time_controller.h" +#include "base/bind.h" +#include "base/callback_helpers.h" #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" @@ -278,7 +280,8 @@ } void AppTimeControllerTest::InstantiateController() { - controller_ = std::make_unique<AppTimeController>(&profile_); + controller_ = std::make_unique<AppTimeController>( + &profile_, base::DoNothing::Repeatedly()); test_api_ = std::make_unique<AppTimeController::TestApi>(controller_.get()); }
diff --git a/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc b/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc index 18eba28..caa50b37 100644 --- a/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc +++ b/chrome/browser/ash/child_accounts/usage_time_limit_processor.cc
@@ -1333,25 +1333,21 @@ return updated_policies; } -void GetEnabledTimeLimitPolicies( - std::set<FamilyUserParentalControlMetrics::TimeLimitPolicyType>* - enabled_policies, +std::set<PolicyType> GetEnabledTimeLimitPolicies( const base::Value& time_limit_prefs) { DCHECK(time_limit_prefs.is_dict()); - if (!enabled_policies) - return; + std::set<PolicyType> enabled_policies; + absl::optional<internal::TimeWindowLimit> time_window_limit = TimeWindowLimitFromPolicy(time_limit_prefs); if (time_window_limit && !time_window_limit->entries.empty()) { - enabled_policies->insert( - FamilyUserParentalControlMetrics::TimeLimitPolicyType::kBedTimeLimit); + enabled_policies.insert(PolicyType::kFixedLimit); } absl::optional<internal::TimeUsageLimit> time_usage_limit = TimeUsageLimitFromPolicy(time_limit_prefs); if (time_usage_limit && !time_usage_limit->entries.empty()) { - enabled_policies->insert(FamilyUserParentalControlMetrics:: - TimeLimitPolicyType::kScreenTimeLimit); + enabled_policies.insert(PolicyType::kUsageLimit); } absl::optional<TimeLimitOverride> time_limit_override = @@ -1360,9 +1356,10 @@ // Ignores the override time limit that is not created within 1 day. if (time_limit_override && now > time_limit_override->created_at() && now - time_limit_override->created_at() < base::TimeDelta::FromDays(1)) { - enabled_policies->insert(FamilyUserParentalControlMetrics:: - TimeLimitPolicyType::kOverrideTimeLimit); + enabled_policies.insert(PolicyType::kOverride); } + + return enabled_policies; } } // namespace usage_time_limit
diff --git a/chrome/browser/ash/child_accounts/usage_time_limit_processor.h b/chrome/browser/ash/child_accounts/usage_time_limit_processor.h index cf9e795..e55d3fb 100644 --- a/chrome/browser/ash/child_accounts/usage_time_limit_processor.h +++ b/chrome/browser/ash/child_accounts/usage_time_limit_processor.h
@@ -15,7 +15,6 @@ #include "base/macros.h" #include "base/time/time.h" -#include "chrome/browser/ash/child_accounts/family_user_parental_control_metrics.h" #include "chromeos/settings/timezone_settings.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -203,12 +202,10 @@ std::set<PolicyType> UpdatedPolicyTypes(const base::Value& old_policy, const base::Value& new_policy); -// Retrieves the the time limit polices in time_limit_prefs and inserts them to -// `enabled_policies`. `time_limit_prefs` is the value of prefs::kUsageTimeLimit -// which stores the usage time limit preference of a user. -void GetEnabledTimeLimitPolicies( - std::set<FamilyUserParentalControlMetrics::TimeLimitPolicyType>* - enabled_policies, +// Returns the active time limit polices in `time_limit_prefs`. +// `time_limit_prefs` is the value of prefs::kUsageTimeLimit which stores the +// usage time limit preference of a user. +std::set<PolicyType> GetEnabledTimeLimitPolicies( const base::Value& time_limit_prefs); } // namespace usage_time_limit
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn index b6b6349..6dc87d3 100644 --- a/chrome/browser/ash/crosapi/BUILD.gn +++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -65,6 +65,8 @@ "metrics_reporting_ash.h", "prefs_ash.cc", "prefs_ash.h", + "remoting_ash.cc", + "remoting_ash.h", "screen_manager_ash.cc", "screen_manager_ash.h", "select_file_ash.cc", @@ -129,6 +131,7 @@ "//extensions/common", "//printing:printing", "//printing:printing_base", + "//remoting/host/chromeos:remoting_service", "//ui/message_center", "//ui/message_center/public/cpp", "//ui/shell_dialogs",
diff --git a/chrome/browser/ash/crosapi/DEPS b/chrome/browser/ash/crosapi/DEPS index 37178cb..e8cc89ba 100644 --- a/chrome/browser/ash/crosapi/DEPS +++ b/chrome/browser/ash/crosapi/DEPS
@@ -6,6 +6,11 @@ "+chrome/browser/ash/crosapi", "+ui/message_center/message_center.h", ], + "remoting_ash\.cc": [ + # For remote support functionality. + "+remoting/host/chromeos/remote_support_host_ash.h", + "+remoting/host/chromeos/remoting_service.h", + ], "screen_manager_ash\.cc": [ # For window parenting. "+ash/shell.h",
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc index 72b4dd29..1581ea7e 100644 --- a/chrome/browser/ash/crosapi/browser_util.cc +++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -55,6 +55,7 @@ #include "chromeos/crosapi/mojom/message_center.mojom.h" #include "chromeos/crosapi/mojom/metrics_reporting.mojom.h" #include "chromeos/crosapi/mojom/prefs.mojom.h" +#include "chromeos/crosapi/mojom/remoting.mojom.h" #include "chromeos/crosapi/mojom/screen_manager.mojom.h" #include "chromeos/crosapi/mojom/system_display.mojom.h" #include "chromeos/crosapi/mojom/task_manager.mojom.h" @@ -233,6 +234,7 @@ MakeInterfaceVersionEntry<crosapi::mojom::MessageCenter>(), MakeInterfaceVersionEntry<crosapi::mojom::MetricsReporting>(), MakeInterfaceVersionEntry<crosapi::mojom::Prefs>(), + MakeInterfaceVersionEntry<crosapi::mojom::Remoting>(), MakeInterfaceVersionEntry<crosapi::mojom::ScreenManager>(), MakeInterfaceVersionEntry<crosapi::mojom::SnapshotCapturer>(), MakeInterfaceVersionEntry<crosapi::mojom::SystemDisplay>(), @@ -261,7 +263,7 @@ } static_assert( - crosapi::mojom::Crosapi::Version_ == 29, + crosapi::mojom::Crosapi::Version_ == 32, "if you add a new crosapi, please add it to kInterfaceVersionEntries"); static_assert(!HasDuplicatedUuid(), "Each Crosapi Mojom interface should have unique UUID.");
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc index 68c8843..7fda5a14 100644 --- a/chrome/browser/ash/crosapi/crosapi_ash.cc +++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -32,6 +32,7 @@ #include "chrome/browser/ash/crosapi/message_center_ash.h" #include "chrome/browser/ash/crosapi/metrics_reporting_ash.h" #include "chrome/browser/ash/crosapi/prefs_ash.h" +#include "chrome/browser/ash/crosapi/remoting_ash.h" #include "chrome/browser/ash/crosapi/screen_manager_ash.h" #include "chrome/browser/ash/crosapi/select_file_ash.h" #include "chrome/browser/ash/crosapi/system_display_ash.h" @@ -106,6 +107,7 @@ prefs_ash_( std::make_unique<PrefsAsh>(g_browser_process->profile_manager(), g_browser_process->local_state())), + remoting_ash_(std::make_unique<RemotingAsh>()), screen_manager_ash_(std::make_unique<ScreenManagerAsh>()), select_file_ash_(std::make_unique<SelectFileAsh>()), system_display_ash_(std::make_unique<SystemDisplayAsh>()), @@ -297,6 +299,10 @@ prefs_ash_->BindReceiver(std::move(receiver)); } +void CrosapiAsh::BindRemoting(mojo::PendingReceiver<mojom::Remoting> receiver) { + remoting_ash_->BindReceiver(std::move(receiver)); +} + void CrosapiAsh::BindUrlHandler( mojo::PendingReceiver<mojom::UrlHandler> receiver) { url_handler_ash_->BindReceiver(std::move(receiver));
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h index 2b29d8d..d815f20c 100644 --- a/chrome/browser/ash/crosapi/crosapi_ash.h +++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -35,6 +35,7 @@ class MessageCenterAsh; class MetricsReportingAsh; class PrefsAsh; +class RemotingAsh; class ScreenManagerAsh; class SelectFileAsh; class SystemDisplayAsh; @@ -93,6 +94,7 @@ void BindMetricsReporting( mojo::PendingReceiver<mojom::MetricsReporting> receiver) override; void BindPrefs(mojo::PendingReceiver<mojom::Prefs> receiver) override; + void BindRemoting(mojo::PendingReceiver<mojom::Remoting> receiver) override; void BindScreenManager( mojo::PendingReceiver<mojom::ScreenManager> receiver) override; void BindSelectFile( @@ -168,6 +170,7 @@ std::unique_ptr<MessageCenterAsh> message_center_ash_; std::unique_ptr<MetricsReportingAsh> metrics_reporting_ash_; std::unique_ptr<PrefsAsh> prefs_ash_; + std::unique_ptr<RemotingAsh> remoting_ash_; std::unique_ptr<ScreenManagerAsh> screen_manager_ash_; std::unique_ptr<SelectFileAsh> select_file_ash_; std::unique_ptr<SystemDisplayAsh> system_display_ash_;
diff --git a/chrome/browser/ash/crosapi/remoting_ash.cc b/chrome/browser/ash/crosapi/remoting_ash.cc new file mode 100644 index 0000000..2009041b --- /dev/null +++ b/chrome/browser/ash/crosapi/remoting_ash.cc
@@ -0,0 +1,45 @@ +// 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/ash/crosapi/remoting_ash.h" + +#include <utility> + +#include "chromeos/crosapi/mojom/remoting.mojom.h" +#include "content/public/browser/browser_thread.h" +#include "remoting/host/chromeos/remote_support_host_ash.h" +#include "remoting/host/chromeos/remoting_service.h" + +namespace crosapi { + +RemotingAsh::RemotingAsh() = default; +RemotingAsh::~RemotingAsh() = default; + +void RemotingAsh::BindReceiver( + mojo::PendingReceiver<mojom::Remoting> receiver) { + receivers_.Add(this, std::move(receiver)); +} + +void RemotingAsh::GetSupportHostDetails( + GetSupportHostDetailsCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + std::move(callback).Run(remoting::RemoteSupportHostAsh::GetHostDetails()); +} + +void RemotingAsh::StartSupportSession( + remoting::mojom::SupportSessionParamsPtr params, + StartSupportSessionCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + remoting::RemotingService::Get().GetSupportHost().StartSession( + std::move(params), + base::BindOnce( + [](StartSupportSessionCallback callback, + remoting::mojom::StartSupportSessionResponsePtr response) { + std::move(callback).Run(std::move(response)); + }, + std::move(callback))); +} + +} // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/remoting_ash.h b/chrome/browser/ash/crosapi/remoting_ash.h new file mode 100644 index 0000000..fc9f0a5 --- /dev/null +++ b/chrome/browser/ash/crosapi/remoting_ash.h
@@ -0,0 +1,38 @@ +// 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_ASH_CROSAPI_REMOTING_ASH_H_ +#define CHROME_BROWSER_ASH_CROSAPI_REMOTING_ASH_H_ + +#include "chromeos/crosapi/mojom/remoting.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" + +namespace crosapi { + +// The ash-chrome implementation of the Remoting crosapi interface. This class +// allows callers to create remote support sessions in ash-chrome from another +// process (e.g. Lacros). This class is affine to the Main/UI thread. +class RemotingAsh : public mojom::Remoting { + public: + RemotingAsh(); + RemotingAsh(const RemotingAsh&) = delete; + RemotingAsh& operator=(const RemotingAsh&) = delete; + ~RemotingAsh() override; + + void BindReceiver(mojo::PendingReceiver<mojom::Remoting> receiver); + + // mojom::Remoting implementation. + void GetSupportHostDetails(GetSupportHostDetailsCallback callback) override; + void StartSupportSession(remoting::mojom::SupportSessionParamsPtr params, + StartSupportSessionCallback callback) override; + + private: + // Support any number of connections. + mojo::ReceiverSet<mojom::Remoting> receivers_; +}; + +} // namespace crosapi + +#endif // CHROME_BROWSER_ASH_CROSAPI_REMOTING_ASH_H_
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc index a870bd9e..df401a6 100644 --- a/chrome/browser/autofill/android/personal_data_manager_android.cc +++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -72,11 +72,27 @@ return GetProfile()->GetPrefs(); } -void MaybeSetRawInfo(AutofillProfile* profile, - autofill::ServerFieldType type, - const base::android::JavaRef<jstring>& jstr) { - if (!jstr.is_null()) - profile->SetRawInfo(type, ConvertJavaStringToUTF16(jstr)); +void MaybeSetRawInfoWithVerificationStatus( + AutofillProfile* profile, + autofill::ServerFieldType type, + const base::android::JavaRef<jstring>& value, + jint status) { + if (value) + profile->SetRawInfoWithVerificationStatus( + type, ConvertJavaStringToUTF16(value), + static_cast<structured_address::VerificationStatus>(status)); +} + +void MaybeSetInfoWithVerificationStatus( + AutofillProfile* profile, + autofill::ServerFieldType type, + const base::android::JavaRef<jstring>& value, + jint status) { + if (value) + profile->SetInfoWithVerificationStatus( + type, ConvertJavaStringToUTF16(value), + g_browser_process->GetApplicationLocale(), + static_cast<structured_address::VerificationStatus>(status)); } // Self-deleting requester of full card details, including full PAN and the CVC @@ -289,23 +305,38 @@ ConvertUTF16ToJavaString( env, profile.GetInfo(AutofillType(NAME_HONORIFIC_PREFIX), g_browser_process->GetApplicationLocale())), + static_cast<jint>(profile.GetVerificationStatus(NAME_HONORIFIC_PREFIX)), ConvertUTF16ToJavaString( env, profile.GetInfo(AutofillType(NAME_FULL), g_browser_process->GetApplicationLocale())), + static_cast<jint>(profile.GetVerificationStatus(NAME_FULL)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(COMPANY_NAME)), + static_cast<jint>(profile.GetVerificationStatus(COMPANY_NAME)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)), + static_cast<jint>( + profile.GetVerificationStatus(ADDRESS_HOME_STREET_ADDRESS)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_STATE)), + static_cast<jint>(profile.GetVerificationStatus(ADDRESS_HOME_STATE)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_CITY)), + static_cast<jint>(profile.GetVerificationStatus(ADDRESS_HOME_CITY)), ConvertUTF16ToJavaString( env, profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)), + static_cast<jint>( + profile.GetVerificationStatus(ADDRESS_HOME_DEPENDENT_LOCALITY)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_ZIP)), + static_cast<jint>(profile.GetVerificationStatus(ADDRESS_HOME_ZIP)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)), + static_cast<jint>( + profile.GetVerificationStatus(ADDRESS_HOME_SORTING_CODE)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)), + static_cast<jint>(profile.GetVerificationStatus(ADDRESS_HOME_COUNTRY)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)), + static_cast<jint>(profile.GetVerificationStatus(PHONE_HOME_WHOLE_NUMBER)), ConvertUTF16ToJavaString(env, profile.GetRawInfo(EMAIL_ADDRESS)), + static_cast<jint>(profile.GetVerificationStatus(EMAIL_ADDRESS)), ConvertUTF8ToJavaString(env, profile.language_code())); } @@ -323,37 +354,52 @@ profile->set_origin( ConvertJavaStringToUTF8(Java_AutofillProfile_getOrigin(env, jprofile))); - profile->SetInfo( - AutofillType(NAME_FULL), - ConvertJavaStringToUTF16(Java_AutofillProfile_getFullName(env, jprofile)), - g_browser_process->GetApplicationLocale()); - MaybeSetRawInfo(profile, autofill::NAME_HONORIFIC_PREFIX, - Java_AutofillProfile_getHonorificPrefix(env, jprofile)); - MaybeSetRawInfo(profile, autofill::COMPANY_NAME, - Java_AutofillProfile_getCompanyName(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_STREET_ADDRESS, - Java_AutofillProfile_getStreetAddress(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_STATE, - Java_AutofillProfile_getRegion(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_CITY, - Java_AutofillProfile_getLocality(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, - Java_AutofillProfile_getDependentLocality(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_ZIP, - Java_AutofillProfile_getPostalCode(env, jprofile)); - MaybeSetRawInfo(profile, autofill::ADDRESS_HOME_SORTING_CODE, - Java_AutofillProfile_getSortingCode(env, jprofile)); - ScopedJavaLocalRef<jstring> country_code = - Java_AutofillProfile_getCountryCode(env, jprofile); - if (!country_code.is_null()) { - profile->SetInfo(AutofillType(ADDRESS_HOME_COUNTRY), - ConvertJavaStringToUTF16(country_code), - g_browser_process->GetApplicationLocale()); - } - MaybeSetRawInfo(profile, autofill::PHONE_HOME_WHOLE_NUMBER, - Java_AutofillProfile_getPhoneNumber(env, jprofile)); - MaybeSetRawInfo(profile, autofill::EMAIL_ADDRESS, - Java_AutofillProfile_getEmailAddress(env, jprofile)); + MaybeSetInfoWithVerificationStatus( + profile, NAME_FULL, Java_AutofillProfile_getFullName(env, jprofile), + Java_AutofillProfile_getFullNameStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, NAME_HONORIFIC_PREFIX, + Java_AutofillProfile_getHonorificPrefix(env, jprofile), + Java_AutofillProfile_getHonorificPrefixStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, COMPANY_NAME, Java_AutofillProfile_getCompanyName(env, jprofile), + Java_AutofillProfile_getCompanyNameStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_STREET_ADDRESS, + Java_AutofillProfile_getStreetAddress(env, jprofile), + Java_AutofillProfile_getStreetAddressStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_STATE, + Java_AutofillProfile_getRegion(env, jprofile), + Java_AutofillProfile_getRegionStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_CITY, + Java_AutofillProfile_getLocality(env, jprofile), + Java_AutofillProfile_getLocalityStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_DEPENDENT_LOCALITY, + Java_AutofillProfile_getDependentLocality(env, jprofile), + Java_AutofillProfile_getDependentLocalityStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_ZIP, + Java_AutofillProfile_getPostalCode(env, jprofile), + Java_AutofillProfile_getPostalCodeStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, ADDRESS_HOME_SORTING_CODE, + Java_AutofillProfile_getSortingCode(env, jprofile), + Java_AutofillProfile_getSortingCodeStatus(env, jprofile)); + MaybeSetInfoWithVerificationStatus( + profile, ADDRESS_HOME_COUNTRY, + Java_AutofillProfile_getCountryCode(env, jprofile), + Java_AutofillProfile_getCountryCodeStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, autofill::PHONE_HOME_WHOLE_NUMBER, + Java_AutofillProfile_getPhoneNumber(env, jprofile), + Java_AutofillProfile_getPhoneNumberStatus(env, jprofile)); + MaybeSetRawInfoWithVerificationStatus( + profile, autofill::EMAIL_ADDRESS, + Java_AutofillProfile_getEmailAddress(env, jprofile), + Java_AutofillProfile_getEmailAddressStatus(env, jprofile)); profile->set_language_code(ConvertJavaStringToUTF8( Java_AutofillProfile_getLanguageCode(env, jprofile))); profile->FinalizeAfterImport();
diff --git a/chrome/browser/autofill/android/save_address_profile_prompt_controller_unittest.cc b/chrome/browser/autofill/android/save_address_profile_prompt_controller_unittest.cc index 4eeb29b..630c900 100644 --- a/chrome/browser/autofill/android/save_address_profile_prompt_controller_unittest.cc +++ b/chrome/browser/autofill/android/save_address_profile_prompt_controller_unittest.cc
@@ -51,15 +51,17 @@ CountryNames::SetLocaleString(GetLocale()); } - // Profile with raw data as it is returned from Java. - AutofillProfile GetFullProfileNoStatus() { + // Profile with verified data as it is returned from Java. + AutofillProfile GetFullProfileWithVerifiedData() { AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); - profile.SetRawInfo(NAME_FULL, u"Mona J. Liza"); + profile.SetRawInfoWithVerificationStatus( + NAME_FULL, u"Mona J. Liza", + structured_address::VerificationStatus::kUserVerified); test::SetProfileInfo(&profile, "", "", "", "email@example.com", "Company Inc.", "33 Narrow Street", "Apt 42", "Playa Vista", "LA", "12345", "US", "13105551234", /*finalize=*/true, - structured_address::VerificationStatus::kNoStatus); + structured_address::VerificationStatus::kUserVerified); return profile; } @@ -139,7 +141,7 @@ ShouldInvokeSaveCallbackWhenUserEditsProfile) { controller_->DisplayPrompt(); - AutofillProfile edited_profile = GetFullProfileNoStatus(); + AutofillProfile edited_profile = GetFullProfileWithVerifiedData(); EXPECT_CALL( decision_callback_, Run(AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted,
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc index c16dea46..2bd8530 100644 --- a/chrome/browser/cart/cart_service.cc +++ b/chrome/browser/cart/cart_service.cc
@@ -12,9 +12,12 @@ #include "chrome/browser/cart/cart_db_content.pb.h" #include "chrome/browser/cart/fetch_discount_worker.h" #include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/common/pref_names.h" #include "chrome/grit/browser_resources.h" #include "chrome/grit/generated_resources.h" +#include "components/optimization_guide/proto/hints.pb.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/search/ntp_features.h" @@ -111,6 +114,12 @@ if (IsCartDiscountEnabled()) { StartGettingDiscount(); } + optimization_guide_decider_ = + OptimizationGuideKeyedServiceFactory::GetForProfile(profile); + if (optimization_guide_decider_) { + optimization_guide_decider_->RegisterOptimizationTypes( + {optimization_guide::proto::SHOPPING_PAGE_PREDICTOR}); + } } CartService::~CartService() = default; @@ -495,6 +504,17 @@ } } +bool CartService::ShouldSkip(const GURL& url) { + if (!optimization_guide_decider_) { + return false; + } + optimization_guide::OptimizationMetadata metadata; + auto decision = optimization_guide_decider_->CanApplyOptimization( + url, optimization_guide::proto::SHOPPING_PAGE_PREDICTOR, &metadata); + DVLOG(1) << "SHOPPING_PAGE_PREDICTOR = " << static_cast<int>(decision); + return optimization_guide::OptimizationGuideDecision::kFalse == decision; +} + void CartService::OnLoadCarts(CartDB::LoadCallback callback, bool success, std::vector<CartDB::KeyAndValue> proto_pairs) { @@ -502,19 +522,23 @@ std::move(callback).Run(success, {}); return; } - std::set<std::string> expired_merchants; + std::set<std::string> merchants_to_erase; for (CartDB::KeyAndValue kv : proto_pairs) { - if (IsExpired(kv.second)) { - DeleteCart(kv.second.key()); - expired_merchants.emplace(kv.second.key()); + if (IsExpired(kv.second) || + ShouldSkip(GURL(kv.second.merchant_cart_url()))) { + // Removed carts should remain removed. + if (!kv.second.is_removed()) { + DeleteCart(kv.second.key()); + } + merchants_to_erase.emplace(kv.second.key()); } } proto_pairs.erase( std::remove_if(proto_pairs.begin(), proto_pairs.end(), - [expired_merchants](CartDB::KeyAndValue kv) { + [merchants_to_erase](CartDB::KeyAndValue kv) { return kv.second.is_hidden() || kv.second.is_removed() || - expired_merchants.find(kv.second.key()) != - expired_merchants.end(); + merchants_to_erase.find(kv.second.key()) != + merchants_to_erase.end(); }), proto_pairs.end()); // Sort items in timestamp descending order.
diff --git a/chrome/browser/cart/cart_service.h b/chrome/browser/cart/cart_service.h index 5038cbc..03ee7b9 100644 --- a/chrome/browser/cart/cart_service.h +++ b/chrome/browser/cart/cart_service.h
@@ -16,6 +16,7 @@ #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_service_observer.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/optimization_guide/content/browser/optimization_guide_decider.h" #include "components/prefs/pref_registry_simple.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -163,7 +164,8 @@ // Set discount_link_fetcher_ for testing purpose. void SetCartDiscountLinkFetcherForTesting( std::unique_ptr<CartDiscountLinkFetcher> discount_link_fetcher); - + // Returns whether a URL should be skipped based on server-side bloom filter. + bool ShouldSkip(const GURL& url); void CacheUsedDiscounts(const cart_db::ChromeCartContentProto& proto); void CleanUpDiscounts(cart_db::ChromeCartContentProto proto); @@ -176,6 +178,7 @@ absl::optional<base::Value> domain_cart_url_mapping_; std::unique_ptr<FetchDiscountWorker> fetch_discount_worker_; std::unique_ptr<CartDiscountLinkFetcher> discount_link_fetcher_; + optimization_guide::OptimizationGuideDecider* optimization_guide_decider_; base::WeakPtrFactory<CartService> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/cart/cart_service_browsertest.cc b/chrome/browser/cart/cart_service_browsertest.cc new file mode 100644 index 0000000..b325d428 --- /dev/null +++ b/chrome/browser/cart/cart_service_browsertest.cc
@@ -0,0 +1,127 @@ +// 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 "base/test/scoped_feature_list.h" +#include "chrome/browser/cart/cart_db_content.pb.h" +#include "chrome/browser/cart/cart_service.h" +#include "chrome/browser/persisted_state_db/profile_proto_db.h" +#include "chrome/test/base/chrome_test_utils.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/optimization_guide/core/optimization_guide_features.h" +#include "components/search/ntp_features.h" +#include "content/public/test/browser_test.h" + +namespace { +cart_db::ChromeCartContentProto BuildProto(const char* domain, + const char* merchant_url) { + cart_db::ChromeCartContentProto proto; + proto.set_key(domain); + proto.set_merchant_cart_url(merchant_url); + proto.set_timestamp(base::Time::Now().ToDoubleT()); + return proto; +} + +const char kMockMerchant[] = "walmart.com"; +const char kMockMerchantURL[] = "https://www.walmart.com"; +using ShoppingCarts = + std::vector<ProfileProtoDB<cart_db::ChromeCartContentProto>::KeyAndValue>; +} // namespace + +// Tests CartService. +class CartServiceBrowserTest : public InProcessBrowserTest { + public: + void SetUpInProcessBrowserTestFixture() override { + scoped_feature_list_.InitWithFeatures( + {ntp_features::kNtpChromeCartModule, + optimization_guide::features::kOptimizationHints}, + {}); + } + + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + Profile* profile = + Profile::FromBrowserContext(web_contents()->GetBrowserContext()); + service_ = CartServiceFactory::GetForProfile(profile); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + // This bloom filter rejects "walmart.com" as a shopping site. + command_line->AppendSwitchASCII("optimization_guide_hints_override", + "Eg8IDxILCBsQJxoFiUzKeE4="); + } + + void OperationEvaluation(base::OnceClosure closure, + bool expected_success, + bool actual_success) { + EXPECT_EQ(expected_success, actual_success); + std::move(closure).Run(); + } + + void GetEvaluationURL(base::OnceClosure closure, + ShoppingCarts expected, + bool result, + ShoppingCarts found) { + EXPECT_EQ(found.size(), expected.size()); + for (size_t i = 0; i < expected.size(); i++) { + EXPECT_EQ(found[i].first, expected[i].first); + EXPECT_EQ(found[i].second.merchant_cart_url(), + expected[i].second.merchant_cart_url()); + for (int j = 0; j < expected[i].second.product_image_urls().size(); j++) { + EXPECT_EQ(expected[i].second.product_image_urls()[j], + found[i].second.product_image_urls()[j]); + } + } + std::move(closure).Run(); + } + + protected: + content::WebContents* web_contents() { + return chrome_test_utils::GetActiveWebContents(this); + } + + base::test::ScopedFeatureList scoped_feature_list_; + CartService* service_; +}; + +IN_PROC_BROWSER_TEST_F(CartServiceBrowserTest, TestNotShowSkippedMerchants) { + CartDB* cart_db_ = service_->GetDB(); + base::RunLoop run_loop[6]; + cart_db::ChromeCartContentProto merchant_proto = + BuildProto(kMockMerchant, kMockMerchantURL); + ShoppingCarts merchant_res = {{kMockMerchant, merchant_proto}}; + ShoppingCarts empty_res = {}; + + cart_db_->AddCart( + kMockMerchant, merchant_proto, + base::BindOnce(&CartServiceBrowserTest::OperationEvaluation, + base::Unretained(this), run_loop[0].QuitClosure(), true)); + run_loop[0].Run(); + + service_->LoadAllActiveCarts(base::BindOnce( + &CartServiceBrowserTest::GetEvaluationURL, base::Unretained(this), + run_loop[1].QuitClosure(), empty_res)); + run_loop[1].Run(); + + cart_db_->LoadAllCarts(base::BindOnce( + &CartServiceBrowserTest::GetEvaluationURL, base::Unretained(this), + run_loop[2].QuitClosure(), empty_res)); + run_loop[2].Run(); + + merchant_proto.set_is_removed(true); + cart_db_->AddCart( + kMockMerchant, merchant_proto, + base::BindOnce(&CartServiceBrowserTest::OperationEvaluation, + base::Unretained(this), run_loop[3].QuitClosure(), true)); + run_loop[3].Run(); + + service_->LoadAllActiveCarts(base::BindOnce( + &CartServiceBrowserTest::GetEvaluationURL, base::Unretained(this), + run_loop[4].QuitClosure(), empty_res)); + run_loop[4].Run(); + + cart_db_->LoadAllCarts(base::BindOnce( + &CartServiceBrowserTest::GetEvaluationURL, base::Unretained(this), + run_loop[5].QuitClosure(), merchant_res)); + run_loop[5].Run(); +}
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc index b7a14cbab..114b62e 100644 --- a/chrome/browser/cart/cart_service_unittest.cc +++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -1041,9 +1041,10 @@ // Tests expired entries are deleted when data is loaded. TEST_F(CartServiceTest, TestExpiredDataDeleted) { - base::RunLoop run_loop[3]; + base::RunLoop run_loop[6]; cart_db::ChromeCartContentProto merchant_proto = BuildProto(kMockMerchantA, kMockMerchantURLA); + const ShoppingCarts result = {{kMockMerchantA, merchant_proto}}; merchant_proto.set_timestamp( (base::Time::Now() - base::TimeDelta::FromDays(16)).ToDoubleT()); @@ -1063,16 +1064,37 @@ run_loop[1].QuitClosure(), kEmptyExpected)); run_loop[1].Run(); - merchant_proto.set_timestamp( - (base::Time::Now() - base::TimeDelta::FromDays(13)).ToDoubleT()); + // If the cart is removed, the expired entry is deleted in load results but is + // kept in database. + merchant_proto.set_is_removed(true); service_->AddCart(kMockMerchantA, absl::nullopt, merchant_proto); task_environment_.RunUntilIdle(); - const ShoppingCarts result = {{kMockMerchantA, merchant_proto}}; service_->LoadAllActiveCarts( base::BindOnce(&CartServiceTest::GetEvaluationURL, base::Unretained(this), - run_loop[2].QuitClosure(), result)); + run_loop[2].QuitClosure(), kEmptyExpected)); run_loop[2].Run(); + + service_->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationURL, base::Unretained(this), + run_loop[3].QuitClosure(), result)); + run_loop[3].Run(); + + merchant_proto.set_timestamp( + (base::Time::Now() - base::TimeDelta::FromDays(13)).ToDoubleT()); + merchant_proto.set_is_removed(false); + service_->GetDB()->AddCart( + kMockMerchantA, merchant_proto, + base::BindOnce(&CartServiceTest::OperationEvaluation, + base::Unretained(this), run_loop[4].QuitClosure(), true)); + run_loop[4].Run(); + + service_->LoadCart( + kMockMerchantA, + base::BindOnce(&CartServiceTest::GetEvaluationCartRemovedStatus, + base::Unretained(this), run_loop[5].QuitClosure(), false)); + run_loop[5].Run(); } // Tests cart-related actions would reshow hidden module.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 2d58c48..d43fff1 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -418,7 +418,7 @@ "//components/webapps/browser", "//printing", "//printing/mojom", - "//remoting/host/it2me:chrome_os_host", + "//remoting/host/chromeos:remoting_service", "//services/audio/public/cpp", "//services/data_decoder/public/cpp", "//services/device/public/cpp/usb",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 5142012a..cc90cd7 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -1344,9 +1344,6 @@ // Cleans up dbus services depending on ash. dbus_services_->PreAshShutdown(); - // Destroy the SystemTokenCertDbStorage global instance. - SystemTokenCertDbStorage::Shutdown(); - // NOTE: Closes ash and destroys ash::Shell. ChromeBrowserMainPartsLinux::PostMainMessageLoopRun(); @@ -1406,7 +1403,7 @@ // The cert database initializer must be shut down before DBus services are // destroyed. - system_token_certdb_initializer_->ShutDown(); + system_token_certdb_initializer_.reset(); // Destroy DBus services immediately after threads are stopped. dbus_services_.reset(); @@ -1417,9 +1414,9 @@ ShutdownDBus(); - // Reset SystemTokenCertDBInitializer after DBus services because it should - // outlive NetworkCertLoader. - system_token_certdb_initializer_.reset(); + // Destroy the SystemTokenCertDbStorage global instance which should outlive + // NetworkCertLoader and |system_token_certdb_initializer_|. + SystemTokenCertDbStorage::Shutdown(); ChromeBrowserMainPartsLinux::PostDestroyThreads();
diff --git a/chrome/browser/chromeos/dbus/vm_applications_service_provider.cc b/chrome/browser/chromeos/dbus/vm_applications_service_provider.cc index ef849940..8c6b158 100644 --- a/chrome/browser/chromeos/dbus/vm_applications_service_provider.cc +++ b/chrome/browser/chromeos/dbus/vm_applications_service_provider.cc
@@ -83,11 +83,14 @@ } Profile* profile = ProfileManager::GetPrimaryUserProfile(); + // Borealis checks Allowed() rather than Enabled() as we need to update the + // borealis applications list before it is considered Enabled (i.e. failure to + // update the list implies failure to enable). if (crostini::CrostiniFeatures::Get()->IsEnabled(profile) || plugin_vm::PluginVmFeatures::Get()->IsEnabled(profile) || borealis::BorealisService::GetForProfile(profile) ->Features() - .IsEnabled()) { + .IsAllowed()) { auto* registry_service = guest_os::GuestOsRegistryServiceFactory::GetForProfile(profile); registry_service->UpdateApplicationList(request);
diff --git a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.cc b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.cc index e96379a..89bd2a5 100644 --- a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.cc +++ b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.cc
@@ -4,9 +4,8 @@ #include "chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.h" -// #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/chromeos/input_method/ui/border_factory.h" -#include "components/vector_icons/vector_icons.h" +#include "chrome/browser/chromeos/input_method/ui/suggestion_details.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" @@ -14,15 +13,20 @@ #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/vector_icons.h" #include "ui/wm/core/window_animations.h" namespace ui { namespace ime { namespace { -constexpr SkColor kButtonHighlightColor = - SkColorSetA(SK_ColorBLACK, 0x0F); // 6% Black. constexpr SkColor kSecondaryIconColor = gfx::kGoogleGrey500; + +bool ShouldHighlight(const views::Button& button) { + return button.GetState() == views::Button::STATE_HOVERED || + button.GetState() == views::Button::STATE_PRESSED; +} + } // namespace GrammarSuggestionWindow::GrammarSuggestionWindow(gfx::NativeView parent, @@ -39,7 +43,7 @@ views::BoxLayout::Orientation::kHorizontal)); suggestion_button_ = - AddChildView(std::make_unique<views::LabelButton>(base::BindRepeating( + AddChildView(std::make_unique<SuggestionView>(base::BindRepeating( &AssistiveDelegate::AssistiveWindowButtonClicked, base::Unretained(delegate_), AssistiveWindowButton{ @@ -61,7 +65,24 @@ }))); ignore_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); ignore_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); + ignore_button_->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY); ignore_button_->SetVisible(true); + + // Highlights buttons when they are hovered or pressed. + const auto update_button_highlight = [](views::Button* button) { + button->SetBackground( + ShouldHighlight(*button) + ? views::CreateSolidBackground(kButtonHighlightColor) + : nullptr); + }; + subscriptions_.insert( + {suggestion_button_, + suggestion_button_->AddStateChangedCallback(base::BindRepeating( + update_button_highlight, base::Unretained(suggestion_button_)))}); + subscriptions_.insert( + {ignore_button_, + ignore_button_->AddStateChangedCallback(base::BindRepeating( + update_button_highlight, base::Unretained(ignore_button_)))}); } GrammarSuggestionWindow::~GrammarSuggestionWindow() = default; @@ -73,7 +94,7 @@ ignore_button_->SetImage( views::Button::ButtonState::STATE_NORMAL, - gfx::CreateVectorIcon(vector_icons::kCloseIcon, kSecondaryIconColor)); + gfx::CreateVectorIcon(views::kCloseIcon, kSecondaryIconColor)); BubbleDialogDelegateView::OnThemeChanged(); } @@ -99,7 +120,7 @@ } void GrammarSuggestionWindow::SetSuggestion(const std::u16string& suggestion) { - suggestion_button_->SetText(suggestion); + suggestion_button_->SetView(SuggestionDetails{.text = suggestion}); } void GrammarSuggestionWindow::SetButtonHighlighted( @@ -128,7 +149,7 @@ } } -views::LabelButton* GrammarSuggestionWindow::GetSuggestionButtonForTesting() { +SuggestionView* GrammarSuggestionWindow::GetSuggestionButtonForTesting() { return suggestion_button_; }
diff --git a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.h b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.h index de680eb..8aff1b8 100644 --- a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.h +++ b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_UI_GRAMMAR_SUGGESTION_WINDOW_H_ #include "chrome/browser/chromeos/input_method/ui/assistive_delegate.h" +#include "chrome/browser/chromeos/input_method/ui/suggestion_view.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/chromeos/ui_chromeos_export.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" @@ -36,7 +37,7 @@ void SetButtonHighlighted(const AssistiveWindowButton& button, bool highlighted); - views::LabelButton* GetSuggestionButtonForTesting(); + SuggestionView* GetSuggestionButtonForTesting(); views::Button* GetIgnoreButtonForTesting(); protected: @@ -44,10 +45,12 @@ private: AssistiveDelegate* delegate_; - views::LabelButton* suggestion_button_; + SuggestionView* suggestion_button_; views::ImageButton* ignore_button_; ButtonId current_highlighted_button_id_ = ButtonId::kNone; + + base::flat_map<views::View*, base::CallbackListSubscription> subscriptions_; }; BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT,
diff --git a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window_unittest.cc b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window_unittest.cc index d519cc56..067f695 100644 --- a/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window_unittest.cc +++ b/chrome/browser/chromeos/input_method/ui/grammar_suggestion_window_unittest.cc
@@ -129,9 +129,9 @@ grammar_suggestion_window_->Show(); grammar_suggestion_window_->SetSuggestion(test_suggestion); - EXPECT_EQ( - grammar_suggestion_window_->GetSuggestionButtonForTesting()->GetText(), - test_suggestion); + EXPECT_EQ(grammar_suggestion_window_->GetSuggestionButtonForTesting() + ->GetSuggestionForTesting(), + test_suggestion); } } // namespace ime
diff --git a/chrome/browser/chromeos/input_method/ui/suggestion_view.cc b/chrome/browser/chromeos/input_method/ui/suggestion_view.cc index 48950fd7..d6b5f5b 100644 --- a/chrome/browser/chromeos/input_method/ui/suggestion_view.cc +++ b/chrome/browser/chromeos/input_method/ui/suggestion_view.cc
@@ -276,6 +276,10 @@ min_width_ = min_width; } +std::u16string SuggestionView::GetSuggestionForTesting() { + return suggestion_label_->GetText(); +} + BEGIN_METADATA(SuggestionView, views::Button) END_METADATA
diff --git a/chrome/browser/chromeos/input_method/ui/suggestion_view.h b/chrome/browser/chromeos/input_method/ui/suggestion_view.h index 2b11832..dd30b3c 100644 --- a/chrome/browser/chromeos/input_method/ui/suggestion_view.h +++ b/chrome/browser/chromeos/input_method/ui/suggestion_view.h
@@ -58,6 +58,8 @@ void SetHighlighted(bool highlighted); void SetMinWidth(int width); + std::u16string GetSuggestionForTesting(); + private: friend class SuggestionWindowViewTest; FRIEND_TEST_ALL_PREFIXES(SuggestionWindowViewTest, ShortcutSettingTest);
diff --git a/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc b/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc index 78264c5..5f8d3b1 100644 --- a/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc +++ b/chrome/browser/chromeos/printing/print_servers_manager_unittest.cc
@@ -8,11 +8,9 @@ #include <memory> #include <string> -#include "ash/constants/ash_features.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/sequenced_task_runner.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/threading/sequenced_task_runner_handle.h" #include "chrome/browser/chromeos/printing/print_servers_provider.h" @@ -89,10 +87,6 @@ class PrintServersManagerTest : public testing::Test, public PrintServersManager::Observer { public: - void SetUp() override { - scoped_feature_list_.InitWithFeatures( - {chromeos::features::kPrintServerScaling}, {}); - } PrintServersManagerTest() { auto server_printers_provider = std::make_unique<FakeServerPrintersProvider>(); @@ -124,8 +118,6 @@ // Everything from PrintServersProvider must be called on Chrome_UIThread content::BrowserTaskEnvironment task_environment_; - base::test::ScopedFeatureList scoped_feature_list_; - // Captured printer lists from observer callbacks. base::flat_map<PrinterClass, std::vector<Printer>> observed_printers_;
diff --git a/chrome/browser/chromeos/printing/print_servers_policy_provider.cc b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc index 932eb8d..d68f2e6 100644 --- a/chrome/browser/chromeos/printing/print_servers_policy_provider.cc +++ b/chrome/browser/chromeos/printing/print_servers_policy_provider.cc
@@ -4,9 +4,7 @@ #include "chrome/browser/chromeos/printing/print_servers_policy_provider.h" -#include "ash/constants/ash_features.h" #include "base/bind.h" -#include "base/feature_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/printing/print_servers_provider.h" #include "chrome/browser/chromeos/printing/print_servers_provider_factory.h" @@ -87,9 +85,6 @@ ServerPrintersFetchingMode PrintServersPolicyProvider::GetFetchingMode( const std::map<GURL, PrintServer>& all_servers) { - if (!base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)) { - return ServerPrintersFetchingMode::kStandard; - } return all_servers.size() <= kMaxRecords ? ServerPrintersFetchingMode::kStandard : ServerPrintersFetchingMode::kSingleServerOnly;
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.cc b/chrome/browser/chromeos/system_token_cert_db_initializer.cc index 1bf7454..cdc8e6e 100644 --- a/chrome/browser/chromeos/system_token_cert_db_initializer.cc +++ b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
@@ -120,17 +120,19 @@ SystemTokenCertDBInitializer::~SystemTokenCertDBInitializer() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); -} - -void SystemTokenCertDBInitializer::ShutDown() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Note that the observer could potentially not be added yet, but // the operation is a no-op in that case. TpmManagerClient::Get()->RemoveObserver(this); - // Cancel any in-progress initialization sequence. - weak_ptr_factory_.InvalidateWeakPtrs(); + // Notify consumers of SystemTokenCertDbStorage that the database is not + // usable anymore. + SystemTokenCertDbStorage::Get()->ResetDatabase(); + + // Destroy the NSSCertDatabase on the IO thread because consumers could be + // accessing it there. + content::GetIOThreadTaskRunner({})->DeleteSoon( + FROM_HERE, std::move(system_token_cert_database_)); } void SystemTokenCertDBInitializer::OnOwnershipTaken() { @@ -243,10 +245,11 @@ /*public_slot=*/std::move(system_slot), /*private_slot=*/crypto::ScopedPK11Slot()); database->SetSystemSlot(std::move(system_slot_copy)); + system_token_cert_database_ = std::move(database); auto* system_token_cert_db_storage = SystemTokenCertDbStorage::Get(); DCHECK(system_token_cert_db_storage); - system_token_cert_db_storage->SetDatabase(std::move(database)); + system_token_cert_db_storage->SetDatabase(system_token_cert_database_.get()); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.h b/chrome/browser/chromeos/system_token_cert_db_initializer.h index 4ab1016..7ee9125 100644 --- a/chrome/browser/chromeos/system_token_cert_db_initializer.h +++ b/chrome/browser/chromeos/system_token_cert_db_initializer.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_TOKEN_CERT_DB_INITIALIZER_H_ #define CHROME_BROWSER_CHROMEOS_SYSTEM_TOKEN_CERT_DB_INITIALIZER_H_ +#include <memory> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" @@ -38,9 +40,6 @@ SystemTokenCertDBInitializer(); ~SystemTokenCertDBInitializer() override; - // Stops making new requests to D-Bus services. - void ShutDown(); - // TpmManagerClient::Observer overrides. void OnOwnershipTaken() override; @@ -88,6 +87,9 @@ // The flag that determines if the system slot can use software fallback. bool is_system_slot_software_fallback_allowed_; + // Global NSSCertDatabase which sees the system token. + std::unique_ptr<net::NSSCertDatabase> system_token_cert_database_; + SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<SystemTokenCertDBInitializer> weak_ptr_factory_{this};
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc b/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc index c6c0621..5f3d35e 100644 --- a/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc +++ b/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc
@@ -42,6 +42,8 @@ const SystemTokenCertDbInitializerTest& other) = delete; ~SystemTokenCertDbInitializerTest() override { + system_token_cert_db_initializer_.reset(); + TpmManagerClient::Shutdown(); NetworkCertLoader::Shutdown(); SystemTokenCertDbStorage::Shutdown();
diff --git a/chrome/browser/content_creation/notes/internal/android/BUILD.gn b/chrome/browser/content_creation/notes/internal/android/BUILD.gn index 8c6d6e5..d3fd175 100644 --- a/chrome/browser/content_creation/notes/internal/android/BUILD.gn +++ b/chrome/browser/content_creation/notes/internal/android/BUILD.gn
@@ -57,6 +57,7 @@ "java/res/layout/carousel_item.xml", "java/res/layout/creation_dialog.xml", "java/res/layout/top_bar.xml", + "java/res/values/dimens.xml", ] }
diff --git a/chrome/browser/content_creation/notes/internal/android/java/res/layout/carousel_item.xml b/chrome/browser/content_creation/notes/internal/android/java/res/layout/carousel_item.xml index 95254c1..b2dcf73b 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/res/layout/carousel_item.xml +++ b/chrome/browser/content_creation/notes/internal/android/java/res/layout/carousel_item.xml
@@ -12,32 +12,18 @@ android:id="@+id/item" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingTop="60dp" - android:paddingEnd="24dp" android:layout_gravity="center_horizontal" - android:orientation="vertical" - android:background="@color/modern_grey_200"> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:paddingTop="4dp" - android:paddingBottom="4dp" - android:paddingLeft="18dp" - android:paddingRight="18dp" - android:layout_marginBottom="17dp" - android:layout_gravity="center_horizontal" - android:background="@drawable/note_title_outline" - android:textAppearance="@style/TextAppearance.TextSmall" /> + android:background="@color/modern_grey_200" + android:orientation="vertical"> <LinearLayout android:id="@+id/background" - android:layout_width="280dp" + android:layout_width="@dimen/note_width" android:layout_height="240dp" android:gravity="center_horizontal" android:background="@drawable/note_background_outline" - android:orientation="vertical"> + android:orientation="vertical" + tools:ignore="UselessParent"> <TextView android:id="@+id/text"
diff --git a/chrome/browser/content_creation/notes/internal/android/java/res/layout/creation_dialog.xml b/chrome/browser/content_creation/notes/internal/android/java/res/layout/creation_dialog.xml index d27d570..9646b97 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/res/layout/creation_dialog.xml +++ b/chrome/browser/content_creation/notes/internal/android/java/res/layout/creation_dialog.xml
@@ -14,14 +14,29 @@ <include layout="@layout/top_bar"/> <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@color/modern_grey_200"> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="60dp" + android:paddingTop="4dp" + android:paddingBottom="4dp" + android:paddingLeft="18dp" + android:paddingRight="18dp" + android:layout_marginBottom="17dp" + android:layout_gravity="center_horizontal" + android:background="@drawable/note_title_outline" + android:textAppearance="@style/TextAppearance.TextSmall" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/note_carousel" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_height="match_parent" android:orientation="horizontal"/> </LinearLayout> </LinearLayout> \ No newline at end of file
diff --git a/chrome/browser/content_creation/notes/internal/android/java/res/values/dimens.xml b/chrome/browser/content_creation/notes/internal/android/java/res/values/dimens.xml new file mode 100644 index 0000000..bebaac7 --- /dev/null +++ b/chrome/browser/content_creation/notes/internal/android/java/res/values/dimens.xml
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<resources> + <dimen name="note_width">280dp</dimen> +</resources>
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java index c6a66946..fcbc8bb 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java +++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationDialog.java
@@ -15,6 +15,7 @@ import androidx.fragment.app.DialogFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.OnScrollListener; import org.chromium.chrome.browser.content_creation.internal.R; import org.chromium.components.content_creation.notes.models.NoteTemplate; @@ -29,6 +30,9 @@ * Dialog for the note creation. */ public class NoteCreationDialog extends DialogFragment { + private static final float FIRST_NOTE_PADDING_RATIO = 0.5f; + private static final float NOTE_PADDING_RATIO = 0.25f; + private View mContentView; private String mSelectedText; @@ -70,6 +74,20 @@ LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false); noteCarousel.setLayoutManager(layoutManager); + + noteCarousel.addOnScrollListener(new OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + LinearLayoutManager layoutManager = + (LinearLayoutManager) recyclerView.getLayoutManager(); + if (layoutManager.findFirstCompletelyVisibleItemPosition() < 0) return; + int selectedItem = layoutManager.findFirstCompletelyVisibleItemPosition(); + ((TextView) mContentView.findViewById(R.id.title)) + .setText(carouselItems.get(selectedItem) + .model.get(NoteProperties.TEMPLATE) + .localizedName); + } + }); } private void bindCarouselItem(PropertyModel model, ViewGroup parent, PropertyKey propertyKey) { @@ -79,13 +97,27 @@ View background = parent.findViewById(R.id.background); template.mainBackground.apply(background); background.setClipToOutline(true); - ((TextView) parent.findViewById(R.id.title)).setText(template.localizedName); - TextView noteText = (TextView) parent.findViewById(R.id.text); noteText.setText(mSelectedText); noteText.setTextColor(template.textStyle.fontColor); noteText.setAllCaps(template.textStyle.allCaps); noteText.setGravity(TextAlignment.toGravity(template.textStyle.alignment)); noteText.setTypeface(typeface); + + setLeftPadding(model.get(NoteProperties.IS_FIRST), parent.findViewById(R.id.item)); + } + + // Adjust the left padding for carousel items, so that the first item is centered and the + // following item is slightlight peaking from the right. For that, set left padding exactly + // what is needed to push the first item to the center, but set a smaller padding for the + // following items. + private void setLeftPadding(boolean is_first, View itemView) { + int dialogWidth = mContentView.getWidth(); + int templateWidth = getActivity().getResources().getDimensionPixelSize(R.dimen.note_width); + int paddingLeft = (int) ((dialogWidth - templateWidth) + * (is_first ? FIRST_NOTE_PADDING_RATIO : NOTE_PADDING_RATIO) + + 0.5f); + itemView.setPadding(paddingLeft, itemView.getPaddingTop(), itemView.getPaddingRight(), + itemView.getPaddingBottom()); } } \ No newline at end of file
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java index 8ff5052..5921e5a1 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java +++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteCreationMediator.java
@@ -86,14 +86,15 @@ continue; } - ListItem listItem = new ListItem( - NoteProperties.NOTE_VIEW_TYPE, buildModel(tuple.template, response.typeface)); + ListItem listItem = new ListItem(NoteProperties.NOTE_VIEW_TYPE, + buildModel(mListModel.size() == 0, tuple.template, response.typeface)); mListModel.add(listItem); } } - private PropertyModel buildModel(NoteTemplate template, Typeface typeface) { + private PropertyModel buildModel(boolean is_first, NoteTemplate template, Typeface typeface) { PropertyModel.Builder builder = new PropertyModel.Builder(NoteProperties.ALL_KEYS) + .with(NoteProperties.IS_FIRST, is_first) .with(NoteProperties.TEMPLATE, template) .with(NoteProperties.TYPEFACE, typeface);
diff --git a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java index 5f6b80b..115408a 100644 --- a/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java +++ b/chrome/browser/content_creation/notes/internal/android/java/src/org/chromium/chrome/browser/content_creation/notes/NoteProperties.java
@@ -15,11 +15,14 @@ public static final int NOTE_VIEW_TYPE = 1; /** The template definition.*/ + static final WritableObjectPropertyKey<Boolean> IS_FIRST = new WritableObjectPropertyKey<>(); + + /** The template definition.*/ static final WritableObjectPropertyKey<NoteTemplate> TEMPLATE = new WritableObjectPropertyKey<>(); /** The Typeface instance that has been loaded for the associated template. */ static final WritableObjectPropertyKey<Typeface> TYPEFACE = new WritableObjectPropertyKey<>(); - static final PropertyKey[] ALL_KEYS = new PropertyKey[] {TEMPLATE, TYPEFACE}; + static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_FIRST, TEMPLATE, TYPEFACE}; } \ No newline at end of file
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_measurement_browsertest.cc b/chrome/browser/data_use_measurement/chrome_data_use_measurement_browsertest.cc index 0f1c2a6..019cf42a 100644 --- a/chrome/browser/data_use_measurement/chrome_data_use_measurement_browsertest.cc +++ b/chrome/browser/data_use_measurement/chrome_data_use_measurement_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h" #include "chrome/browser/profiles/profile.h" @@ -81,8 +82,8 @@ } }; -// Flaky on Linux (and Linux MSAN): https://crbug.com/1141975. -#if defined(OS_LINUX) +// Flaky on Linux (and Linux MSAN) and ChromeOS: https://crbug.com/1141975. +#if defined(OS_LINUX) || defined(OS_CHROMEOS) #define MAYBE_DataUseTrackerPrefsUpdated DISABLED_DataUseTrackerPrefsUpdated #else #define MAYBE_DataUseTrackerPrefsUpdated DataUseTrackerPrefsUpdated
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc index 634e8bf..17fb2fd 100644 --- a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc +++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc
@@ -175,6 +175,10 @@ std::string raw_public_key; if (!key_pair_->ExportRawPublicKey(&raw_public_key)) return std::string(); + // This is intentionally using a non-standard format for the uncompressed + // point length, so we trim the leading 0x04 byte. See + // https://crbug.com/1212786 + raw_public_key.erase(0, 1); std::string public_key; if (!CreatePEMKey(raw_public_key, KeyType::PUBLIC_KEY, public_key)) return std::string();
diff --git a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc index acf2220c1f..27ea027 100644 --- a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc +++ b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.cc
@@ -21,7 +21,6 @@ "enterprise_connectors.file_system.%s.access_token"; constexpr char kRefreshTokenPrefPathTemplate[] = "enterprise_connectors.file_system.%s.refresh_token"; -constexpr char kBoxProviderName[] = "box"; // Traffic annotation strings must be fully defined at compile time. They // can't be dynamically built at runtime based on the |service_provider|.
diff --git a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h index 1d90cbd..89ed87a 100644 --- a/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h +++ b/chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h
@@ -15,6 +15,11 @@ namespace enterprise_connectors { +// The unique key for the Box service provider. This is used to generate the +// correct network annotation tag as well as possible parameters in the +// access token consent URL. +constexpr char kBoxProviderName[] = "box"; + // Helper class to retrieve an access token for a file system service provider. class AccessTokenFetcher : public OAuth2AccessTokenFetcherImpl, public OAuth2AccessTokenConsumer {
diff --git a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc index 0e776db..5af4616 100644 --- a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc +++ b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.cc
@@ -19,6 +19,7 @@ #include "google_apis/gaia/oauth2_access_token_consumer.h" #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "google_apis/gaia/oauth2_api_call_flow.h" +#include "net/base/escape.h" #include "net/base/url_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -76,6 +77,10 @@ std::string query = base::StringPrintf("client_id=%s&response_type=code", settings_.client_id.c_str()); + std::string extra_params = GetProviderSpecificUrlParameters(); + if (!extra_params.empty()) + base::StringAppendF(&query, "&%s", extra_params.c_str()); + url::Replacements<char> replacements; replacements.SetQuery(query.c_str(), url::Component(0, query.length())); GURL url = settings_.authorization_endpoint.ReplaceComponents(replacements); @@ -192,6 +197,24 @@ GetWidget()->Close(); } +std::string FileSystemSigninDialogDelegate::GetProviderSpecificUrlParameters() { + // If an email domain is specified, use it as a hint in the box authn URL. + // Make sure the domain has an @ prefix. + if (settings_.service_provider == kBoxProviderName) { + if (!settings_.email_domain.empty()) { + // If the domain does not already start with an @ sign, prepend the + // escaped version of it. + return base::StringPrintf( + "box_login=%s%s", settings_.email_domain[0] == '@' ? "" : "%40", + net::EscapeQueryParamValue(settings_.email_domain, true).c_str()); + } + } else { + NOTREACHED() << "Unknown service provider: " << settings_.service_provider; + } + + return std::string(); +} + BEGIN_METADATA(FileSystemSigninDialogDelegate, views::DialogDelegateView) END_METADATA
diff --git a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.h b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.h index ccb19760..25375c3 100644 --- a/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.h +++ b/chrome/browser/enterprise/connectors/file_system/signin_dialog_delegate.h
@@ -75,6 +75,10 @@ const std::string& access_token, const std::string& refresh_token); + // Return extra URL parameters that are specific to a given service provider. + // May return the empty string if there are none. + std::string GetProviderSpecificUrlParameters(); + const FileSystemSettings settings_; std::unique_ptr<views::WebView> web_view_; std::unique_ptr<OAuth2AccessTokenFetcherImpl> token_fetcher_;
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index a979865..75e582e0 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -297,6 +297,19 @@ return seen; } +void WaitForExtraHeadersListener(base::WaitableEvent* event, + content::BrowserContext* browser_context) { + if (BrowserContextKeyedAPIFactory<WebRequestAPI>::Get(browser_context) + ->HasExtraHeadersListenerForTesting()) { + event->Signal(); + return; + } + + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&WaitForExtraHeadersListener, event, browser_context)); +} + } // namespace class ExtensionWebRequestApiTest : public ExtensionApiTest { @@ -2405,6 +2418,87 @@ redirect_successful_listener.extension_id_for_message()); } +// Regression test for http://crbug.com/1074282. +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, StaleHeadersAfterRedirect) { + TestExtensionDir test_dir; + test_dir.WriteManifest(R"({ + "name": "Web Request Stale Headers Test", + "manifest_version": 2, + "version": "0.1", + "background": { "scripts": ["background.js"] }, + "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"] + })"); + test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"( + window.locationCount = 0; + window.requestCount = 0; + chrome.test.sendMessage('ready', function(reply) { + chrome.webRequest.onResponseStarted.addListener(function(details) { + window.requestCount++; + var headers = details.responseHeaders; + for (var i = 0; i < headers.length; i++) { + if (headers[i].name === 'Location') { + window.locationCount++; + } + } + }, + {urls: ['<all_urls>'], types: ['xmlhttprequest']}, + ['responseHeaders', 'extraHeaders'] + ); + }); + )"); + + ExtensionTestMessageListener listener("ready", true); + const Extension* extension = LoadExtension(test_dir.UnpackedPath()); + ASSERT_TRUE(extension); + EXPECT_TRUE(listener.WaitUntilSatisfied()); + + auto task_runner = base::SequencedTaskRunnerHandle::Get(); + embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting( + [&](const net::test_server::HttpRequest& request) + -> std::unique_ptr<net::test_server::HttpResponse> { + if (request.relative_url != "/redirect-and-wait") + return nullptr; + + // Wait for the listener to be installed before proceeding. + base::WaitableEvent unblock( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + // Post a task to the UI thread since the request handler runs on a + // background thread. + task_runner->PostTask(FROM_HERE, base::BindLambdaForTesting([&] { + listener.Reply(""); + WaitForExtraHeadersListener( + &unblock, browser()->profile()); + })); + unblock.Wait(); + + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_MOVED_PERMANENTLY); + http_response->AddCustomHeader( + "Location", embedded_test_server()->GetURL("/echo").spec()); + return http_response; + })); + ASSERT_TRUE(embedded_test_server()->Start()); + + // Navigate to a basic page so XHR requests work. + ui_test_utils::NavigateToURL(browser(), + embedded_test_server()->GetURL("/echo")); + + // Make a XHR request which redirects. The final response should not include + // the Location header. + auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + PerformXhrInFrame(web_contents->GetMainFrame(), + embedded_test_server()->host_port_pair().host(), + embedded_test_server()->port(), "redirect-and-wait"); + EXPECT_EQ( + GetCountFromBackgroundPage(extension, profile(), "window.requestCount"), + 1); + EXPECT_EQ( + GetCountFromBackgroundPage(extension, profile(), "window.locationCount"), + 0); +} + IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ChangeHeaderUMAs) { using RequestHeaderType = extension_web_request_api_helpers::RequestHeaderType;
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index ea14f698..12314e1 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -2432,6 +2432,45 @@ mojom::APIPermissionID::kStorage)); } +// Tests that a Manifest V3 extension's service worker can't be used to relax +// the extension CSP. +IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, + ExtensionCSPModification_MV3) { + ExtensionTestMessageListener worker_listener("ready", false); + const Extension* extension = LoadExtension(test_data_dir_.AppendASCII( + "service_worker/worker_based_background/extension_csp_modification")); + ASSERT_TRUE(extension); + const ExtensionId extension_id = extension->id(); + ASSERT_TRUE(worker_listener.WaitUntilSatisfied()); + + ExtensionTestMessageListener csp_modified_listener( + "script-src 'self'; object-src 'self';", false); + csp_modified_listener.set_extension_id(extension_id); + ui_test_utils::NavigateToURL( + browser(), extension->GetResourceURL("extension_page.html")); + EXPECT_TRUE(csp_modified_listener.WaitUntilSatisfied()); + + // Ensure the inline script is not executed because we ensure that the + // extension's CSP is applied in the renderer (even though the service worker + // removed it). + constexpr char kScript[] = R"( + (() => { + try { + scriptExecuted; + window.domAutomationController.send('FAIL'); + } catch (e) { + const result = e.message.includes('scriptExecuted is not defined') + ? 'PASS' : 'FAIL'; + window.domAutomationController.send(result); + } + })(); + )"; + std::string result; + ASSERT_TRUE(content::ExecuteScriptAndExtractString( + browser()->tab_strip_model()->GetActiveWebContents(), kScript, &result)); + EXPECT_EQ("PASS", result); +} + // Tests that console messages logged by extension service workers, both via // the typical console.* methods and via our custom bindings console, are // passed through the normal ServiceWorker console messaging and are
diff --git a/chrome/browser/extensions/window_open_interactive_apitest.cc b/chrome/browser/extensions/window_open_interactive_apitest.cc index 71d3890..6a4e56f 100644 --- a/chrome/browser/extensions/window_open_interactive_apitest.cc +++ b/chrome/browser/extensions/window_open_interactive_apitest.cc
@@ -9,7 +9,13 @@ namespace extensions { -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenFocus) { +// Fails flakily on Mac. https://crbug.com/1216102 +#if defined(OS_MAC) +#define MAYBE_WindowOpenFocus DISABLED_WindowOpenFocus +#else +#define MAYBE_WindowOpenFocus WindowOpenFocus +#endif +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_WindowOpenFocus) { ASSERT_TRUE(RunExtensionTest("window_open/focus")) << message_; }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 7c09172..5e6f2e8 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -4238,21 +4238,11 @@ "expiry_milestone": 88 }, { - "name": "print-server-scaling", - "owners": [ "mattme" ], - "expiry_milestone": 92 - }, - { "name": "print-with-reduced-rasterization", "owners": [ "thestig" ], "expiry_milestone": 96 }, { - "name": "printer-status-dialog", - "owners": [ "gavinwill", "cros-peripherals@google.com" ], - "expiry_milestone": 91 - }, - { "name": "privacy-advisor", "owners": [ "harrisonsean", @@ -5182,6 +5172,11 @@ "expiry_milestone": 98 }, { + "name": "use-passthrough-command-decoder", + "owners": [ "//third_party/angle/OWNERS" ], + "expiry_milestone": 100 + }, + { "name": "use-search-click-for-right-click", "owners": [ "zentaro", "cros-peripherals@google.com" ], "expiry_milestone": 95
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 82d780c6..48b5ce9 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1996,10 +1996,6 @@ "Enables the new prerenderer implementation for <link rel=prerender> " "instead of NoStatePrefetch."; -const char kPrintServerScalingName[] = "Print Server Scaling"; -const char kPrintServerScalingDescription[] = - "Allows print servers to be selected when beyond a specified limit."; - const char kPrivacyAdvisorName[] = "Privacy Advisor"; const char kPrivacyAdvisorDescription[] = "Provides contextual entry points for adjusting privacy settings"; @@ -2106,12 +2102,6 @@ "page that has been hidden for 5 minutes. For additional details, see " "https://www.chromestatus.com/feature/4718288976216064."; -const char kPrinterStatusDialogName[] = - "Show printer status on destination dialog"; -const char kPrinterStatusDialogDescription[] = - "Enables printer status icons and labels for saved printers on the Print " - "Preview destination dialog"; - const char kSafetyTipName[] = "Show Safety Tip UI when visiting low-reputation websites"; const char kSafetyTipDescription[] = @@ -2736,6 +2726,12 @@ const char kSanitizerApiDescription[] = "Enable the Sanitizer API. See: https://github.com/WICG/sanitizer-api"; +const char kUsePassthroughCommandDecoderName[] = + "Use passthrough command decoder"; +const char kUsePassthroughCommandDecoderDescription[] = + "Use chrome passthrough command decoder instead of validating command " + "decoder."; + // Android --------------------------------------------------------------------- #if defined(OS_ANDROID) @@ -4147,11 +4143,6 @@ "Enables the embedded Assistant UI in the app list. Requires Assistant to " "be enabled."; -const char kEnableAssistantMediaSessionIntegrationName[] = - "Assistant Media Session integration"; -const char kEnableAssistantMediaSessionIntegrationDescription[] = - "Enable Assistant Media Session Integration."; - const char kEnableAssistantRoutinesName[] = "Assistant Routines"; const char kEnableAssistantRoutinesDescription[] = "Enable Assistant Routines.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 1e30edbd..eea1a5a 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1145,9 +1145,6 @@ extern const char kPrerender2Name[]; extern const char kPrerender2Description[]; -extern const char kPrintServerScalingName[]; -extern const char kPrintServerScalingDescription[]; - extern const char kPrivacyAdvisorName[]; extern const char kPrivacyAdvisorDescription[]; @@ -1213,9 +1210,6 @@ extern const char kIntensiveWakeUpThrottlingName[]; extern const char kIntensiveWakeUpThrottlingDescription[]; -extern const char kPrinterStatusDialogName[]; -extern const char kPrinterStatusDialogDescription[]; - extern const char kSafetyTipName[]; extern const char kSafetyTipDescription[]; @@ -1580,6 +1574,9 @@ extern const char kSanitizerApiName[]; extern const char kSanitizerApiDescription[]; +extern const char kUsePassthroughCommandDecoderName[]; +extern const char kUsePassthroughCommandDecoderDescription[]; + // Android -------------------------------------------------------------------- #if defined(OS_ANDROID) @@ -2392,9 +2389,6 @@ extern const char kEnableAssistantLauncherUIName[]; extern const char kEnableAssistantLauncherUIDescription[]; -extern const char kEnableAssistantMediaSessionIntegrationName[]; -extern const char kEnableAssistantMediaSessionIntegrationDescription[]; - extern const char kEnableAssistantRoutinesName[]; extern const char kEnableAssistantRoutinesDescription[];
diff --git a/chrome/browser/metrics/perf/cpu_identity.cc b/chrome/browser/metrics/perf/cpu_identity.cc index b5f21ba..8cc21ea 100644 --- a/chrome/browser/metrics/perf/cpu_identity.cc +++ b/chrome/browser/metrics/perf/cpu_identity.cc
@@ -12,6 +12,8 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/system/sys_info.h" +#include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace metrics { @@ -101,7 +103,14 @@ CPUIdentity GetCPUIdentity() { CPUIdentity result = {}; result.arch = base::SysInfo::OperatingSystemArchitecture(); - result.release = base::SysInfo::OperatingSystemVersion(); + result.release = +#if BUILDFLAG(IS_CHROMEOS_ASH) + base::SysInfo::KernelVersion(); +#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) + base::SysInfo::OperatingSystemVersion(); +#else +#error "Unsupported configuration" +#endif base::CPU cpuid; result.vendor = cpuid.vendor_name(); result.family = cpuid.family();
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index 2c7672a..aa82d6d 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -65,8 +65,9 @@ static const base::FilePath::CharType* const kLocalAccessAllowList[] = { "/home/chronos/user/Downloads", "/home/chronos/user/MyFiles", - "/home/chronos/user/log", "/home/chronos/user/WebRTC Logs", + "/home/chronos/user/google-assistant-library/log", + "/home/chronos/user/log", "/media", "/opt/oem", "/run/arc/sdcard/write/emulated/0",
diff --git a/chrome/browser/net/chrome_network_delegate_unittest.cc b/chrome/browser/net/chrome_network_delegate_unittest.cc index 02d4f86..1ddff91 100644 --- a/chrome/browser/net/chrome_network_delegate_unittest.cc +++ b/chrome/browser/net/chrome_network_delegate_unittest.cc
@@ -59,8 +59,10 @@ EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/Downloads", "")); EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/MyFiles", "")); EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/MyFiles/file.pdf", "")); - EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/log", "")); EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/WebRTC Logs", "")); + EXPECT_TRUE( + IsAccessAllowed("/home/chronos/user/google-assistant-library/log", "")); + EXPECT_TRUE(IsAccessAllowed("/home/chronos/user/log", "")); EXPECT_TRUE(IsAccessAllowed("/media", "")); EXPECT_TRUE(IsAccessAllowed("/opt/oem", "")); EXPECT_TRUE(IsAccessAllowed("/usr/share/chromeos-assets", ""));
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index 71ea49e..1049fc0 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -3054,8 +3054,9 @@ 1); } +// Flaky on all platforms: https://crbug.com/1211028. // Tests that a portal activation records metrics. -IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, PortalActivation) { +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, DISABLED_PortalActivation) { // We only record metrics for portals when the time is consistent across // processes. if (!base::TimeTicks::IsConsistentAcrossProcesses())
diff --git a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc index 3a430ee..072c7c4 100644 --- a/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc +++ b/chrome/browser/password_manager/multi_profile_credentials_filter_unittest.cc
@@ -45,10 +45,6 @@ return nullptr; } void ShowProfileCustomizationBubble(Browser* browser) override {} - void ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) override {} }; class TestPasswordManagerClient
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc index bddcf11d..92f2902 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -17,10 +17,8 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/account_id_from_account_info.h" #include "chrome/browser/signin/signin_util.h" -#include "chrome/common/pref_names.h" #include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" -#include "components/prefs/pref_change_registrar.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/consent_level.h" #include "content/public/browser/notification_details.h" @@ -51,13 +49,6 @@ // happens in the background after PKS initialization - so this service // should always be created before the oauth token is available. DCHECK(!CanApplyPoliciesForSignedInUser(/*check_for_refresh_token=*/true)); - - profile_pref_change_registrar_.Init(profile->GetPrefs()); - profile_pref_change_registrar_.Add( - prefs::kUserAcceptedAccountManagement, - base::BindRepeating( - &UserPolicySigninService::OnAccountManagementPrefChange, - base::Unretained(this))); } UserPolicySigninService::~UserPolicySigninService() { @@ -155,8 +146,6 @@ return; } - profile_pref_change_registrar_.RemoveAll(); - InitializeForSignedInUser( AccountIdFromAccountInfo( identity_manager()->GetPrimaryAccountInfo(consent_level())), @@ -165,11 +154,6 @@ ->GetURLLoaderFactoryForBrowserProcess()); } -void UserPolicySigninService::OnAccountManagementPrefChange() { - if (CanApplyPoliciesForSignedInUser(/*check_for_refresh_token=*/true)) - TryInitializeForSignedInUser(); -} - void UserPolicySigninService::InitializeUserCloudPolicyManager( const AccountId& account_id, std::unique_ptr<CloudPolicyClient> client) {
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h index 8a8b83c..6d9c042 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service.h +++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "chrome/browser/policy/cloud/user_policy_signin_service_base.h" -#include "components/prefs/pref_change_registrar.h" #include "components/signin/public/identity_manager/identity_manager.h" class AccountId; @@ -87,9 +86,6 @@ // cloud policy. void ProhibitSignoutIfNeeded(); - // Called when the value of the `profile.account_management` pref changes. - void OnAccountManagementPrefChange(); - // Helper method that attempts calls |InitializeForSignedInUser| only if // |policy_manager| is not-nul. Expects that there is a refresh token for // the primary account. @@ -100,7 +96,6 @@ PolicyRegistrationCallback callback); std::unique_ptr<CloudPolicyClientRegistrationHelper> registration_helper_; - PrefChangeRegistrar profile_pref_change_registrar_; DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService); };
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index 5d919e4..038f37b 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -124,6 +124,9 @@ */ public static final String CHROME_DEFAULT_BROWSER = "applink.chrome_default_browser"; + /** Number of attempts that have been made to download a survey. */ + public static final KeyPrefix CHROME_SURVEY_DOWNLOAD_ATTEMPTS = + new KeyPrefix("Chrome.Survey.DownloadAttempts.*"); /** * Key prefix used to indicate the timestamps when the survey info bar is displayed for a * certain survey. @@ -993,6 +996,7 @@ APP_LAUNCH_LAST_KNOWN_ACTIVE_TAB_STATE, APP_LAUNCH_SEARCH_ENGINE_HAD_LOGO, APPLICATION_OVERRIDE_LANGUAGE, + CHROME_SURVEY_DOWNLOAD_ATTEMPTS.pattern(), CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.pattern(), CLIPBOARD_SHARED_URI, CLIPBOARD_SHARED_URI_TIMESTAMP,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js index b82ee9c..118ff64 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -3074,9 +3074,13 @@ const site = `<a tabindex=0></a><p>start</p><a tabindex=0></a><p>end</p>`; this.runWithLoadedTree(site, function(root) { assertEquals( - RoleType.ANCHOR, ChromeVoxState.instance.currentRange.start.node.role); + RoleType.STATIC_TEXT, + ChromeVoxState.instance.currentRange.start.node.role); - mockFeedback.call(doCmd('readFromHere')) + // "start" is uttered twice, once for the initial focus as the page loads, + // and once during the 'read from here' command. + mockFeedback.expectSpeech('start') + .call(doCmd('readFromHere')) .expectSpeech('start', 'end') .replay(); });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/bluetooth_braille_display_manager.js b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/bluetooth_braille_display_manager.js index d4ee205..8a6512a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/bluetooth_braille_display_manager.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/bluetooth_braille_display_manager.js
@@ -52,16 +52,52 @@ * utilize Brltty (e.g. BrailleBack). * @private {!Array<string|RegExp>} */ - this.displayNames_ = [ - '"EL12-', 'Esys-', 'Focus 14 BT', 'Focus 40 BT', 'Brailliant BI', - /Hansone|HansoneXL|BrailleSense|BrailleEDGE|SmartBeetle/, - 'Refreshabraille', 'Orbit', 'Baum SuperVario', 'VarioConnect', - 'VarioUltra', 'HWG Brailliant', 'braillex trio', /Alva BC/i, 'TSM', 'TS5', - new RegExp( - '(Actilino.*|Active Star.*|Braille Wave( BRW)?|Braillino( BL2)?' + - '|Braille Star 40( BS4)?|Easy Braille( EBR)?|Active Braille( AB4)?' + - '|Basic Braille BB[3,4,6]?)\\/[a-zA-Z][0-9]-[0-9]{5}'), - new RegExp('(BRW|BL2|BS4|EBR|AB4|BB(3|4|6)?)\\/[a-zA-Z][0-9]-[0-9]{5}') + this.displayNamePrefixes_ = [ + 'Actilino ALO', + 'Activator AC4', + 'Active Braille AB', + 'Active Star AS', + 'ALVA BC', + 'APH Chameleon', + 'APH Mantis', + 'Basic Braille BB', + 'Basic Braille Plus BP', + 'BAUM Conny', + 'Baum PocketVario', + 'Baum SuperVario', + 'Baum SVario', + 'BrailleConnect', + 'BrailleEDGE', + 'BrailleMe', + 'BMpk', + 'BMsmart', + 'BM32', + 'BrailleNote Touch', + 'BrailleSense', + 'Braille Star', + 'Braillex', + 'Brailliant BI', + 'Brailliant 14', + 'Brailliant 80', + 'Braillino BL', + 'B2G', + 'Conny', + 'Easy Braille EBR', + 'EL12-', + 'Esys-', + 'Focus', + 'Humanware BrailleOne', + 'HWG Brailliant', + 'MB248', + 'NLS eReader', + 'Orbit Reader', + 'Pronto!', + 'Refreshabraille', + 'SmartBeetle', + 'SuperVario', + 'TSM', + 'VarioConnect', + 'VarioUltra' ]; /** @@ -187,7 +223,7 @@ handleDevicesChanged(opt_device) { chrome.bluetooth.getDevices((devices) => { const displayList = devices.filter((device) => { - return this.displayNames_.some((name) => { + return this.displayNamePrefixes_.some((name) => { return device.name && device.name.search(name) === 0; }); });
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn index 397a1b6..eafc30c 100644 --- a/chrome/browser/resources/extensions/BUILD.gn +++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -61,18 +61,18 @@ out_folder = "$target_gen_dir/$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_manifest" in_files = [ - "drag_and_drop_handler.js", - "extensions.js", + "drag_and_drop_handler.ts", + "extensions.ts", "item_behavior.js", - "item_util.js", - "keyboard_shortcut_delegate.js", - "navigation_helper.js", - "service.js", - "shortcut_util.js", + "item_util.ts", + "keyboard_shortcut_delegate.ts", + "navigation_helper.ts", + "service.ts", + "shortcut_util.ts", ] if (is_chromeos_ash) { - in_files += [ "kiosk_browser_proxy.js" ] + in_files += [ "kiosk_browser_proxy.ts" ] } } @@ -93,7 +93,7 @@ "drop_overlay.js", "error_page.js", "host_permissions_toggle_list.js", - "icons.js", + "icons.ts", "install_warnings_dialog.js", "item.js", "item_list.js", @@ -105,8 +105,8 @@ "pack_dialog.js", "runtime_host_permissions.js", "runtime_hosts_dialog.js", - "shared_style.js", - "shared_vars.js", + "shared_style.ts", + "shared_vars.ts", "shortcut_input.js", "sidebar.js", "toggle_row.js", @@ -133,7 +133,7 @@ "drop_overlay.js", "error_page.js", "host_permissions_toggle_list.js", - "icons.js", + "icons.ts", "install_warnings_dialog.js", "item.js", "item_list.js", @@ -145,8 +145,8 @@ "pack_dialog_alert.js", "runtime_host_permissions.js", "runtime_hosts_dialog.js", - "shared_style.js", - "shared_vars.js", + "shared_style.ts", + "shared_vars.ts", "shortcut_input.js", "sidebar.js", "toggle_row.js", @@ -188,32 +188,32 @@ "checkup.js", "code_section.js", "detail_view.js", - "drag_and_drop_handler.js", + "drag_and_drop_handler.ts", "drop_overlay.js", "error_page.js", - "extensions.js", + "extensions.ts", "host_permissions_toggle_list.js", - "icons.js", + "icons.ts", "install_warnings_dialog.js", "item_behavior.js", "item.js", "item_list.js", - "item_util.js", - "keyboard_shortcut_delegate.js", + "item_util.ts", + "keyboard_shortcut_delegate.ts", "keyboard_shortcuts.js", "load_error.js", "manager.js", - "navigation_helper.js", + "navigation_helper.ts", "options_dialog.js", "pack_dialog_alert.js", "pack_dialog.js", "runtime_host_permissions.js", "runtime_hosts_dialog.js", - "service.js", - "shared_style.js", - "shared_vars.js", + "service.ts", + "shared_style.ts", + "shared_vars.ts", "shortcut_input.js", - "shortcut_util.js", + "shortcut_util.ts", "sidebar.js", "toggle_row.js", "toolbar.js", @@ -221,12 +221,14 @@ definitions = [ "//tools/typescript/definitions/activity_log_private.d.ts", "//tools/typescript/definitions/developer_private.d.ts", + "//tools/typescript/definitions/management.d.ts", "//tools/typescript/definitions/metrics_private.d.ts", + "//tools/typescript/definitions/runtime.d.ts", ] if (is_chromeos_ash) { in_files += [ - "kiosk_browser_proxy.js", + "kiosk_browser_proxy.ts", "kiosk_dialog.js", ] definitions += [ "//tools/typescript/definitions/chrome_send.d.ts" ]
diff --git a/chrome/browser/resources/extensions/drag_and_drop_handler.js b/chrome/browser/resources/extensions/drag_and_drop_handler.ts similarity index 72% rename from chrome/browser/resources/extensions/drag_and_drop_handler.js rename to chrome/browser/resources/extensions/drag_and_drop_handler.ts index 8930b614..76d9ce64 100644 --- a/chrome/browser/resources/extensions/drag_and_drop_handler.js +++ b/chrome/browser/resources/extensions/drag_and_drop_handler.ts
@@ -7,21 +7,16 @@ import {Service} from './service.js'; -/** @implements DragWrapperDelegate */ -export class DragAndDropHandler { - /** - * @param {boolean} dragEnabled - * @param {!EventTarget} target - */ - constructor(dragEnabled, target) { - this.dragEnabled = dragEnabled; +export class DragAndDropHandler implements DragWrapperDelegate { + dragEnabled: boolean; + private eventTarget_: EventTarget; - /** @private {!EventTarget} */ + constructor(dragEnabled: boolean, target: EventTarget) { + this.dragEnabled = dragEnabled; this.eventTarget_ = target; } - /** @override */ - shouldAcceptDrag(e) { + shouldAcceptDrag(e: DragEvent): boolean { // External Extension installation can be disabled globally, e.g. while a // different overlay is already showing. if (!this.dragEnabled) { @@ -32,29 +27,26 @@ // wait until 'drop' to decide whether to do something with the file or // not. // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p - return !!e.dataTransfer.types && e.dataTransfer.types.indexOf('Files') > -1; + return !!e.dataTransfer!.types && + e.dataTransfer!.types.indexOf('Files') > -1; } - /** @override */ doDragEnter() { Service.getInstance().notifyDragInstallInProgress(); this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-started')); } - /** @override */ doDragLeave() { this.fireDragEnded_(); } - /** @override */ - doDragOver(e) { + doDragOver(e: DragEvent) { e.preventDefault(); } - /** @override */ - doDrop(e) { + doDrop(e: DragEvent) { this.fireDragEnded_(); - if (e.dataTransfer.files.length !== 1) { + if (e.dataTransfer!.files.length !== 1) { return; } @@ -62,11 +54,11 @@ // Files lack a check if they're a directory, but we can find out through // its item entry. - const item = e.dataTransfer.items[0]; + const item = e.dataTransfer!.items[0]; if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) { handled = true; this.handleDirectoryDrop_(); - } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) { + } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer!.files[0].name)) { // Only process files that look like extensions. Other files should // navigate the browser normally. handled = true; @@ -80,25 +72,22 @@ /** * Handles a dropped file. - * @private */ - handleFileDrop_() { + private handleFileDrop_() { Service.getInstance().installDroppedFile(); } /** * Handles a dropped directory. - * @private */ - handleDirectoryDrop_() { + private handleDirectoryDrop_() { Service.getInstance().loadUnpackedFromDrag().catch(loadError => { this.eventTarget_.dispatchEvent( new CustomEvent('drag-and-drop-load-error', {detail: loadError})); }); } - /** @private */ - fireDragEnded_() { + private fireDragEnded_() { this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended')); } }
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.ts similarity index 100% rename from chrome/browser/resources/extensions/extensions.js rename to chrome/browser/resources/extensions/extensions.ts
diff --git a/chrome/browser/resources/extensions/icons.js b/chrome/browser/resources/extensions/icons.ts similarity index 100% rename from chrome/browser/resources/extensions/icons.js rename to chrome/browser/resources/extensions/icons.ts
diff --git a/chrome/browser/resources/extensions/item_util.js b/chrome/browser/resources/extensions/item_util.ts similarity index 68% rename from chrome/browser/resources/extensions/item_util.js rename to chrome/browser/resources/extensions/item_util.ts index b6ac452..97192bf8 100644 --- a/chrome/browser/resources/extensions/item_util.js +++ b/chrome/browser/resources/extensions/item_util.ts
@@ -7,41 +7,36 @@ import {assertNotReached} from 'chrome://resources/js/assert.m.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +export enum SourceType { + WEBSTORE = 'webstore', + POLICY = 'policy', + SIDELOADED = 'sideloaded', + UNPACKED = 'unpacked', + UNKNOWN = 'unknown', +} -// Closure compiler won't let this be declared inside cr.define(). -/** @enum {string} */ -export const SourceType = { - WEBSTORE: 'webstore', - POLICY: 'policy', - SIDELOADED: 'sideloaded', - UNPACKED: 'unpacked', - UNKNOWN: 'unknown', -}; - -/** @enum {string} */ -export const EnableControl = { - RELOAD: 'RELOAD', - REPAIR: 'REPAIR', - ENABLE_TOGGLE: 'ENABLE_TOGGLE', -}; +export enum EnableControl { + RELOAD = 'RELOAD', + REPAIR = 'REPAIR', + ENABLE_TOGGLE = 'ENABLE_TOGGLE', +} // TODO(tjudkins): This should be extracted to a shared metrics module. /** @enum {string} */ -export const UserAction = { - ALL_TOGGLED_ON: 'Extensions.Settings.HostList.AllHostsToggledOn', - ALL_TOGGLED_OFF: 'Extensions.Settings.HostList.AllHostsToggledOff', - SPECIFIC_TOGGLED_ON: 'Extensions.Settings.HostList.SpecificHostToggledOn', - SPECIFIC_TOGGLED_OFF: 'Extensions.Settings.HostList.SpecificHostToggledOff', - LEARN_MORE: 'Extensions.Settings.HostList.LearnMoreActivated', -}; +export enum UserAction { + ALL_TOGGLED_ON = 'Extensions.Settings.HostList.AllHostsToggledOn', + ALL_TOGGLED_OFF = 'Extensions.Settings.HostList.AllHostsToggledOff', + SPECIFIC_TOGGLED_ON = 'Extensions.Settings.HostList.SpecificHostToggledOn', + SPECIFIC_TOGGLED_OFF = 'Extensions.Settings.HostList.SpecificHostToggledOff', + LEARN_MORE = 'Extensions.Settings.HostList.LearnMoreActivated', +} /** * Returns true if the extension is enabled, including terminated * extensions. - * @param {!chrome.developerPrivate.ExtensionState} state - * @return {boolean} */ -export function isEnabled(state) { +export function isEnabled(state: chrome.developerPrivate.ExtensionState): + boolean { switch (state) { case chrome.developerPrivate.ExtensionState.ENABLED: case chrome.developerPrivate.ExtensionState.TERMINATED: @@ -51,15 +46,15 @@ return false; } assertNotReached(); + return false; } /** - * Returns true if the user can change whether or not the extension is - * enabled. - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {boolean} + * @return {boolean} Whether the user can change whether or not the extension is + * enabled. */ -export function userCanChangeEnablement(item) { +export function userCanChangeEnablement( + item: chrome.developerPrivate.ExtensionInfo): boolean { // User doesn't have permission. if (!item.userMayModify) { return false; @@ -84,11 +79,8 @@ return true; } -/** - * @param {!chrome.developerPrivate.ExtensionInfo} item - * @return {SourceType} - */ -export function getItemSource(item) { +export function getItemSource(item: chrome.developerPrivate.ExtensionInfo): + SourceType { if (item.controlledInfo) { return SourceType.POLICY; } @@ -107,11 +99,7 @@ assertNotReached(item.location); } -/** - * @param {SourceType} source - * @return {string} - */ -export function getItemSourceString(source) { +export function getItemSourceString(source: SourceType): string { switch (source) { case SourceType.POLICY: return loadTimeData.getString('itemSourcePolicy'); @@ -127,14 +115,14 @@ return ''; } assertNotReached(); + return ''; } /** * Computes the human-facing label for the given inspectable view. - * @param {!chrome.developerPrivate.ExtensionView} view - * @return {string} */ -export function computeInspectableViewLabel(view) { +export function computeInspectableViewLabel( + view: chrome.developerPrivate.ExtensionView): string { // Trim the "chrome-extension://<id>/". const url = new URL(view.url); let label = view.url; @@ -162,21 +150,17 @@ } /** - * Returns true if the extension is in the terminated state. - * @param {!chrome.developerPrivate.ExtensionState} state - * @return {boolean} - * @private + * @return Whether the extension is in the terminated state. */ -function isTerminated_(state) { +function isTerminated_(state: chrome.developerPrivate.ExtensionState): boolean { return state === chrome.developerPrivate.ExtensionState.TERMINATED; } /** * Determines which enable control to display for a given extension. - * @param {!chrome.developerPrivate.ExtensionInfo} data - * @return {EnableControl} */ -export function getEnableControl(data) { +export function getEnableControl(data: chrome.developerPrivate.ExtensionInfo): + EnableControl { if (isTerminated_(data.state)) { return EnableControl.RELOAD; }
diff --git a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js deleted file mode 100644 index 4281304e..0000000 --- a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js +++ /dev/null
@@ -1,35 +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. - -'use strict'; - -/** @interface */ -export class KeyboardShortcutDelegate { - /** - * Called when shortcut capturing changes in order to suspend or re-enable - * global shortcut handling. This is important so that the shortcuts aren't - * processed normally as the user types them. - * TODO(devlin): From very brief experimentation, it looks like preventing - * the default handling on the event also does this. Investigate more in the - * future. - * @param {boolean} isCapturing - */ - setShortcutHandlingSuspended(isCapturing) {} - - /** - * Updates an extension command's keybinding. - * @param {string} extensionId - * @param {string} commandName - * @param {string} keybinding - */ - updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {} - - /** - * Updates an extension command's scope. - * @param {string} extensionId - * @param {string} commandName - * @param {chrome.developerPrivate.CommandScope} scope - */ - updateExtensionCommandScope(extensionId, commandName, scope) {} -}
diff --git a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.ts b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.ts new file mode 100644 index 0000000..c76bf5ff --- /dev/null +++ b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.ts
@@ -0,0 +1,28 @@ +// 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. + +export interface KeyboardShortcutDelegate { + /** + * Called when shortcut capturing changes in order to suspend or re-enable + * global shortcut handling. This is important so that the shortcuts aren't + * processed normally as the user types them. + * TODO(devlin): From very brief experimentation, it looks like preventing + * the default handling on the event also does this. Investigate more in the + * future. + */ + setShortcutHandlingSuspended(isCapturing: boolean): void; + + /** + * Updates an extension command's keybinding. + */ + updateExtensionCommandKeybinding( + extensionId: string, commandName: string, keybinding: string): void; + + /** + * Updates an extension command's scope. + */ + updateExtensionCommandScope( + extensionId: string, commandName: string, + scope: chrome.developerPrivate.CommandScope): void; +}
diff --git a/chrome/browser/resources/extensions/kiosk_browser_proxy.js b/chrome/browser/resources/extensions/kiosk_browser_proxy.js deleted file mode 100644 index 79f1dcb..0000000 --- a/chrome/browser/resources/extensions/kiosk_browser_proxy.js +++ /dev/null
@@ -1,113 +0,0 @@ -// 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. - -/** - * @fileoverview A helper object used from the "Kiosk" dialog to interact with - * the browser. - */ - -import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; - -/** - * @typedef {{ - * kioskEnabled: boolean, - * autoLaunchEnabled: boolean - * }} - */ -let KioskSettings; - -/** - * @typedef {{ - * id: string, - * name: string, - * iconURL: string, - * autoLaunch: boolean, - * isLoading: boolean - * }} - */ -export let KioskApp; - -/** - * @typedef {{ - * apps: !Array<!KioskApp>, - * disableBailout: boolean, - * hasAutoLaunchApp: boolean - * }} - */ -export let KioskAppSettings; - -/** @interface */ -export class KioskBrowserProxy { - /** @param {string} appId */ - addKioskApp(appId) {} - - /** @param {string} appId */ - disableKioskAutoLaunch(appId) {} - - /** @param {string} appId */ - enableKioskAutoLaunch(appId) {} - - /** @return {!Promise<!KioskAppSettings>} */ - getKioskAppSettings() {} - - /** @return {!Promise<!KioskSettings>} */ - initializeKioskAppSettings() {} - - /** @param {string} appId */ - removeKioskApp(appId) {} - - /** @param {boolean} disableBailout */ - setDisableBailoutShortcut(disableBailout) {} -} - -/** @implements {KioskBrowserProxy} */ -export class KioskBrowserProxyImpl { - /** @override */ - initializeKioskAppSettings() { - return sendWithPromise('initializeKioskAppSettings'); - } - - /** @override */ - getKioskAppSettings() { - return sendWithPromise('getKioskAppSettings'); - } - - /** @override */ - addKioskApp(appId) { - chrome.send('addKioskApp', [appId]); - } - - /** @override */ - disableKioskAutoLaunch(appId) { - chrome.send('disableKioskAutoLaunch', [appId]); - } - - /** @override */ - enableKioskAutoLaunch(appId) { - chrome.send('enableKioskAutoLaunch', [appId]); - } - - /** @override */ - removeKioskApp(appId) { - chrome.send('removeKioskApp', [appId]); - } - - /** @override */ - setDisableBailoutShortcut(disableBailout) { - chrome.send('setDisableBailoutShortcut', [disableBailout]); - } - - /** @return {!KioskBrowserProxy} */ - static getInstance() { - return instance || (instance = new KioskBrowserProxyImpl()); - } - - /** @param {!KioskBrowserProxy} obj */ - static setInstance(obj) { - instance = obj; - } -} - -/** @type {?KioskBrowserProxy} */ -let instance = null;
diff --git a/chrome/browser/resources/extensions/kiosk_browser_proxy.ts b/chrome/browser/resources/extensions/kiosk_browser_proxy.ts new file mode 100644 index 0000000..83f1daf --- /dev/null +++ b/chrome/browser/resources/extensions/kiosk_browser_proxy.ts
@@ -0,0 +1,80 @@ +// 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. + +/** + * @fileoverview A helper object used from the "Kiosk" dialog to interact with + * the browser. + */ + +import {sendWithPromise} from 'chrome://resources/js/cr.m.js'; + +type KioskSettings = { + kioskEnabled: boolean, + autoLaunchEnabled: boolean, +}; + +export type KioskApp = { + id: string, + name: string, + iconURL: string, + autoLaunch: boolean, + isLoading: boolean, +}; + +export type KioskAppSettings = { + apps: Array<KioskApp>, + disableBailout: boolean, + hasAutoLaunchApp: boolean, +}; + +/** @interface */ +export interface KioskBrowserProxy { + addKioskApp(appId: string): void; + disableKioskAutoLaunch(appId: string): void; + enableKioskAutoLaunch(appId: string): void; + getKioskAppSettings(): Promise<KioskAppSettings>; + initializeKioskAppSettings(): Promise<KioskSettings>; + removeKioskApp(appId: string): void; + setDisableBailoutShortcut(disableBailout: boolean): void; +} + +export class KioskBrowserProxyImpl implements KioskBrowserProxy { + initializeKioskAppSettings() { + return sendWithPromise('initializeKioskAppSettings'); + } + + getKioskAppSettings() { + return sendWithPromise('getKioskAppSettings'); + } + + addKioskApp(appId: string) { + chrome.send('addKioskApp', [appId]); + } + + disableKioskAutoLaunch(appId: string) { + chrome.send('disableKioskAutoLaunch', [appId]); + } + + enableKioskAutoLaunch(appId: string) { + chrome.send('enableKioskAutoLaunch', [appId]); + } + + removeKioskApp(appId: string) { + chrome.send('removeKioskApp', [appId]); + } + + setDisableBailoutShortcut(disableBailout: boolean) { + chrome.send('setDisableBailoutShortcut', [disableBailout]); + } + + static getInstance(): KioskBrowserProxy { + return instance || (instance = new KioskBrowserProxyImpl()); + } + + static setInstance(obj: KioskBrowserProxy) { + instance = obj; + } +} + +let instance: KioskBrowserProxy|null = null;
diff --git a/chrome/browser/resources/extensions/navigation_helper.js b/chrome/browser/resources/extensions/navigation_helper.ts similarity index 73% rename from chrome/browser/resources/extensions/navigation_helper.js rename to chrome/browser/resources/extensions/navigation_helper.ts index 53de02b..9ed4800 100644 --- a/chrome/browser/resources/extensions/navigation_helper.js +++ b/chrome/browser/resources/extensions/navigation_helper.ts
@@ -8,34 +8,29 @@ /** * The different pages that can be shown at a time. * Note: This must remain in sync with the page ids in manager.html! - * @enum {string} */ -export const Page = { - LIST: 'items-list', - DETAILS: 'details-view', - ACTIVITY_LOG: 'activity-log', - SHORTCUTS: 'keyboard-shortcuts', - ERRORS: 'error-page', +export enum Page { + LIST = 'items-list', + DETAILS = 'details-view', + ACTIVITY_LOG = 'activity-log', + SHORTCUTS = 'keyboard-shortcuts', + ERRORS = 'error-page', +} + +export enum Dialog { + OPTIONS = 'options', +} + +export type PageState = { + page: Page, + extensionId?: string, + subpage?: Dialog, }; -/** @enum {string} */ -export const Dialog = { - OPTIONS: 'options', -}; +type Listener = (pageState: PageState) => void; -/** - * @typedef {{page: Page, - * extensionId: (string|undefined), - * subpage: (!Dialog|undefined)}} - */ -export let PageState; - -/** - * @param {!PageState} a - * @param {!PageState} b - * @return {boolean} Whether a and b are equal. - */ -function isPageStateEqual(a, b) { +/** @return Whether a and b are equal. */ +function isPageStateEqual(a: PageState, b: PageState): boolean { return a.page === b.page && a.subpage === b.subpage && a.extensionId === b.extensionId; } @@ -43,9 +38,8 @@ /** * Regular expression that captures the leading slash, the content and the * trailing slash in three different groups. - * @const {!RegExp} */ -const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/; +const CANONICAL_PATH_REGEX: RegExp = /(^\/)([\/-\w]+)(\/$)/; /** * A helper object to manage in-page navigations. Since the extensions page @@ -53,25 +47,19 @@ * page), we use this object to manage the history and url conversions. */ export class NavigationHelper { + private nextListenerId_: number = 1; + private listeners_: Map<number, Listener> = new Map(); + private previousPage_: PageState; + constructor() { this.processRoute_(); - /** @private {number} */ - this.nextListenerId_ = 1; - - /** @private {!Map<number, function(!PageState)>} */ - this.listeners_ = new Map(); - - /** @private {!PageState} */ - this.previousPage_; - window.addEventListener('popstate', () => { this.notifyRouteChanged_(this.getCurrentPage()); }); } - /** @private */ - get currentPath_() { + private get currentPath_(): string { return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2'); } @@ -79,9 +67,8 @@ * Going to /configureCommands and /shortcuts should land you on /shortcuts. * These are the only two supported routes, so all other cases will redirect * you to root path if not already on it. - * @private */ - processRoute_() { + private processRoute_() { if (this.currentPath_ === '/configureCommands' || this.currentPath_ === '/shortcuts') { window.history.replaceState( @@ -92,10 +79,9 @@ } /** - * @return {!PageState} The page that should be displayed for the - * current URL. + * @return The page that should be displayed for the current URL. */ - getCurrentPage() { + getCurrentPage(): PageState { const search = new URLSearchParams(location.search); let id = search.get('id'); if (id) { @@ -124,9 +110,9 @@ /** * Function to add subscribers. * @param {!function(!PageState)} listener - * @return {number} A numerical ID to be used for removing the listener. + * @return A numerical ID to be used for removing the listener. */ - addListener(listener) { + addListener(listener: Listener): number { const nextListenerId = this.nextListenerId_++; this.listeners_.set(nextListenerId, listener); return nextListenerId; @@ -134,28 +120,26 @@ /** * Remove a previously registered listener. - * @param {number} id - * @return {boolean} Whether a listener with the given ID was actually found - * and removed. + * @return Whether a listener with the given ID was actually found and + * removed. */ - removeListener(id) { + removeListener(id: number): boolean { return this.listeners_.delete(id); } /** * Function to notify subscribers. - * @private */ - notifyRouteChanged_(newPage) { - this.listeners_.forEach((listener, id) => { + private notifyRouteChanged_(newPage: PageState) { + for (const listener of this.listeners_.values()) { listener(newPage); - }); + } } /** - * @param {!PageState} newPage the page to navigate to. + * @param newPage the page to navigate to. */ - navigateTo(newPage) { + navigateTo(newPage: PageState) { const currentPage = this.getCurrentPage(); if (currentPage && isPageStateEqual(currentPage, newPage)) { return; @@ -166,10 +150,9 @@ } /** - * @param {!PageState} newPage the page to replace the current - * page with. + * @param newPage the page to replace the current page with. */ - replaceWith(newPage) { + replaceWith(newPage: PageState) { this.updateHistory(newPage, true /* replaceState */); if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) { // Skip the duplicate history entry. @@ -181,10 +164,8 @@ /** * Called when a page changes, and pushes state to history to reflect it. - * @param {!PageState} entry - * @param {boolean} replaceState */ - updateHistory(entry, replaceState) { + updateHistory(entry: PageState, replaceState: boolean) { let path; switch (entry.page) { case Page.LIST:
diff --git a/chrome/browser/resources/extensions/service.js b/chrome/browser/resources/extensions/service.ts similarity index 73% rename from chrome/browser/resources/extensions/service.js rename to chrome/browser/resources/extensions/service.ts index 03bb069..85438ac 100644 --- a/chrome/browser/resources/extensions/service.js +++ b/chrome/browser/resources/extensions/service.ts
@@ -20,22 +20,16 @@ * @implements {ActivityLogEventDelegate} * @implements {ErrorPageDelegate} * @implements {ItemDelegate} - * @implements {KeyboardShortcutDelegate} * @implements {LoadErrorDelegate} * @implements {PackDialogDelegate} * @implements {ToolbarDelegate} */ -export class Service { - constructor() { - /** @private {boolean} */ - this.isDeleting_ = false; - - /** @private {!Set<string>} */ - this.eventsToIgnoreOnce_ = new Set(); - } +export class Service implements KeyboardShortcutDelegate { + private isDeleting_: boolean = false; + private eventsToIgnoreOnce_: Set<string> = new Set(); getProfileConfiguration() { - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { chrome.developerPrivate.getProfileConfiguration(resolve); }); } @@ -44,20 +38,14 @@ return chrome.developerPrivate.onItemStateChanged; } - /** - * @param {string} extensionId - * @param {!chrome.developerPrivate.EventType} eventType - * @return {boolean} - */ - shouldIgnoreUpdate(extensionId, eventType) { + shouldIgnoreUpdate( + extensionId: string, + eventType: chrome.developerPrivate.EventType): boolean { return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`); } - /** - * @param {string} extensionId - * @param {!chrome.developerPrivate.EventType} eventType - */ - ignoreNextEvent(extensionId, eventType) { + ignoreNextEvent( + extensionId: string, eventType: chrome.developerPrivate.EventType): void { this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`); } @@ -66,21 +54,21 @@ } getExtensionsInfo() { - return new Promise(function(resolve, reject) { + return new Promise(function(resolve) { chrome.developerPrivate.getExtensionsInfo( {includeDisabled: true, includeTerminated: true}, resolve); }); } /** @override */ - getExtensionSize(id) { - return new Promise(function(resolve, reject) { + getExtensionSize(id: string): Promise<string> { + return new Promise(function(resolve) { chrome.developerPrivate.getExtensionSize(id, resolve); }); } /** @override */ - addRuntimeHostPermission(id, host) { + addRuntimeHostPermission(id: string, host: string): Promise<void> { return new Promise((resolve, reject) => { chrome.developerPrivate.addHostPermission(id, host, () => { if (chrome.runtime.lastError) { @@ -93,7 +81,7 @@ } /** @override */ - removeRuntimeHostPermission(id, host) { + removeRuntimeHostPermission(id: string, host: string): Promise<void> { return new Promise((resolve, reject) => { chrome.developerPrivate.removeHostPermission(id, host, () => { if (chrome.runtime.lastError) { @@ -106,18 +94,17 @@ } /** @override */ - recordUserAction(metricName) { + recordUserAction(metricName: string): void { chrome.metricsPrivate.recordUserAction(metricName); } /** * Opens a file browser dialog for the user to select a file (or directory). - * @param {chrome.developerPrivate.SelectType} selectType - * @param {chrome.developerPrivate.FileType} fileType - * @return {Promise<string>} The promise to be resolved with the selected - * path. + * @return The promise to be resolved with the selected path. */ - chooseFilePath_(selectType, fileType) { + chooseFilePath_( + selectType: chrome.developerPrivate.SelectType, + fileType: chrome.developerPrivate.FileType): Promise<string> { return new Promise(function(resolve, reject) { chrome.developerPrivate.choosePath(selectType, fileType, function(path) { if (chrome.runtime.lastError && @@ -132,7 +119,8 @@ } /** @override */ - updateExtensionCommandKeybinding(extensionId, commandName, keybinding) { + updateExtensionCommandKeybinding( + extensionId: string, commandName: string, keybinding: string) { chrome.developerPrivate.updateExtensionCommand({ extensionId: extensionId, commandName: commandName, @@ -141,7 +129,9 @@ } /** @override */ - updateExtensionCommandScope(extensionId, commandName, scope) { + updateExtensionCommandScope( + extensionId: string, commandName: string, + scope: chrome.developerPrivate.CommandScope): void { // The COMMAND_REMOVED event needs to be ignored since it is sent before // the command is added back with the updated scope but can be handled // after the COMMAND_ADDED event. @@ -156,17 +146,16 @@ /** @override */ - setShortcutHandlingSuspended(isCapturing) { + setShortcutHandlingSuspended(isCapturing: boolean) { chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing); } /** - * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options - * @return {!Promise} A signal that loading finished, rejected if any error - * occurred. - * @private + * @return A signal that loading finished, rejected if any error occurred. */ - loadUnpackedHelper_(opt_options) { + private loadUnpackedHelper_(opt_options?: + chrome.developerPrivate.LoadUnpackedOptions): + Promise<boolean> { return new Promise(function(resolve, reject) { const options = Object.assign( { @@ -193,7 +182,7 @@ } /** @override */ - deleteItem(id) { + deleteItem(id: string) { if (this.isDeleting_) { return; } @@ -209,7 +198,7 @@ } /** @override */ - setItemEnabled(id, isEnabled) { + setItemEnabled(id: string, isEnabled: boolean) { chrome.metricsPrivate.recordUserAction( isEnabled ? 'Extensions.ExtensionEnabled' : 'Extensions.ExtensionDisabled'); @@ -217,7 +206,7 @@ } /** @override */ - setItemAllowedIncognito(id, isAllowedIncognito) { + setItemAllowedIncognito(id: string, isAllowedIncognito: boolean) { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, incognitoAccess: isAllowedIncognito, @@ -225,7 +214,7 @@ } /** @override */ - setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) { + setItemAllowedOnFileUrls(id: string, isAllowedOnFileUrls: boolean) { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, fileAccess: isAllowedOnFileUrls, @@ -233,7 +222,8 @@ } /** @override */ - setItemHostAccess(id, hostAccess) { + setItemHostAccess(id: string, hostAccess: chrome.developerPrivate.HostAccess): + void { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, hostAccess: hostAccess, @@ -241,7 +231,7 @@ } /** @override */ - setItemCollectsErrors(id, collectsErrors) { + setItemCollectsErrors(id: string, collectsErrors: boolean): void { chrome.developerPrivate.updateExtensionConfiguration({ extensionId: id, errorCollection: collectsErrors, @@ -249,7 +239,8 @@ } /** @override */ - inspectItemView(id, view) { + inspectItemView(id: string, view: chrome.developerPrivate.ExtensionView): + void { chrome.developerPrivate.openDevTools({ extensionId: id, renderProcessId: view.renderProcessId, @@ -259,16 +250,12 @@ }); } - /** - * @param {string} url - * @override - */ - openUrl(url) { + openUrl(url: string): void { window.open(url); } /** @override */ - reloadItem(id) { + reloadItem(id: string): Promise<void> { return new Promise(function(resolve, reject) { chrome.developerPrivate.reload( id, {failQuietly: true, populateErrorForUnpacked: true}, @@ -284,14 +271,14 @@ } /** @override */ - repairItem(id) { + repairItem(id: string): void { chrome.developerPrivate.repairExtension(id); } /** @override */ - showItemOptionsPage(extension) { + showItemOptionsPage(extension: chrome.developerPrivate.ExtensionInfo): void { assert(extension && extension.optionsPage); - if (extension.optionsPage.openInTab) { + if (extension.optionsPage!.openInTab) { chrome.developerPrivate.showOptions(extension.id); } else { navigation.navigateTo({ @@ -303,51 +290,56 @@ } /** @override */ - setProfileInDevMode(inDevMode) { + setProfileInDevMode(inDevMode: boolean) { chrome.developerPrivate.updateProfileConfiguration( {inDeveloperMode: inDevMode}); } /** @override */ - loadUnpacked() { + loadUnpacked(): Promise<boolean> { return this.loadUnpackedHelper_(); } /** @override */ - retryLoadUnpacked(retryGuid) { + retryLoadUnpacked(retryGuid: string): Promise<boolean> { // Attempt to load an unpacked extension, optionally as another attempt at // a previously-specified load. return this.loadUnpackedHelper_({retryGuid: retryGuid}); } /** @override */ - choosePackRootDirectory() { + choosePackRootDirectory(): Promise<string> { return this.chooseFilePath_( chrome.developerPrivate.SelectType.FOLDER, chrome.developerPrivate.FileType.LOAD); } /** @override */ - choosePrivateKeyPath() { + choosePrivateKeyPath(): Promise<string> { return this.chooseFilePath_( chrome.developerPrivate.SelectType.FILE, chrome.developerPrivate.FileType.PEM); } /** @override */ - packExtension(rootPath, keyPath, flag, callback) { + packExtension( + rootPath: string, keyPath: string, flag?: number, + callback?: + (response: chrome.developerPrivate.PackDirectoryResponse) => void): + void { chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback); } /** @override */ - updateAllExtensions(extensions) { + updateAllExtensions(extensions: chrome.developerPrivate.ExtensionInfo[]): + Promise<string> { /** * Attempt to reload local extensions. If an extension fails to load, the * user is prompted to try updating the broken extension using loadUnpacked * and we skip reloading the remaining local extensions. */ - return new Promise((resolve) => { - chrome.developerPrivate.autoUpdate(resolve); + return new Promise<void>((resolve) => { + chrome.developerPrivate.autoUpdate(() => resolve()); chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions'); }) .then(() => { @@ -371,7 +363,9 @@ } /** @override */ - deleteErrors(extensionId, errorIds, type) { + deleteErrors( + extensionId: string, errorIds?: number[], + type?: chrome.developerPrivate.ErrorType) { chrome.developerPrivate.deleteExtensionErrors({ extensionId: extensionId, errorIds: errorIds, @@ -380,20 +374,21 @@ } /** @override */ - requestFileSource(args) { - return new Promise(function(resolve, reject) { + requestFileSource(args: chrome.developerPrivate.RequestFileSourceProperties): + Promise<chrome.developerPrivate.RequestFileSourceResponse> { + return new Promise(function(resolve) { chrome.developerPrivate.requestFileSource(args, resolve); }); } /** @override */ - showInFolder(id) { + showInFolder(id: string) { chrome.developerPrivate.showPath(id); } /** @override */ - getExtensionActivityLog(extensionId) { - return new Promise(function(resolve, reject) { + getExtensionActivityLog(extensionId: string) { + return new Promise(function(resolve) { chrome.activityLogPrivate.getExtensionActivities( { activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY, @@ -404,7 +399,7 @@ } /** @override */ - getFilteredExtensionActivityLog(extensionId, searchTerm) { + getFilteredExtensionActivityLog(extensionId: string, searchTerm: string) { const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY; // Construct one filter for each API call we will make: one for substring @@ -428,10 +423,13 @@ } ]; - const promises = activityLogFilters.map( - filter => new Promise(function(resolve, reject) { - chrome.activityLogPrivate.getExtensionActivities(filter, resolve); - })); + const promises: + Array<Promise<chrome.activityLogPrivate.ActivityResultSet>> = + activityLogFilters.map( + filter => new Promise(function(resolve) { + chrome.activityLogPrivate.getExtensionActivities( + filter, resolve); + })); return Promise.all(promises).then(results => { // We may have results that are present in one or more searches, so @@ -449,15 +447,15 @@ } /** @override */ - deleteActivitiesById(activityIds) { - return new Promise(function(resolve, reject) { + deleteActivitiesById(activityIds: string[]): Promise<void> { + return new Promise(function(resolve) { chrome.activityLogPrivate.deleteActivities(activityIds, resolve); }); } /** @override */ - deleteActivitiesFromExtension(extensionId) { - return new Promise(function(resolve, reject) { + deleteActivitiesFromExtension(extensionId: string): Promise<void> { + return new Promise(function(resolve) { chrome.activityLogPrivate.deleteActivitiesByExtension( extensionId, resolve); }); @@ -469,7 +467,7 @@ } /** @override */ - downloadActivities(rawActivityData, fileName) { + downloadActivities(rawActivityData: string, fileName: string) { const blob = new Blob([rawActivityData], {type: 'application/json'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); @@ -494,16 +492,13 @@ chrome.developerPrivate.notifyDragInstallInProgress(); } - /** @return {!Service} */ - static getInstance() { + static getInstance(): Service { return instance || (instance = new Service()); } - /** @param {!Service} obj */ - static setInstance(obj) { + static setInstance(obj: Service) { instance = obj; } } -/** @type {?Service} */ -let instance = null; +let instance: Service|null = null;
diff --git a/chrome/browser/resources/extensions/shared_style.js b/chrome/browser/resources/extensions/shared_style.ts similarity index 100% rename from chrome/browser/resources/extensions/shared_style.js rename to chrome/browser/resources/extensions/shared_style.ts
diff --git a/chrome/browser/resources/extensions/shared_vars.js b/chrome/browser/resources/extensions/shared_vars.ts similarity index 100% rename from chrome/browser/resources/extensions/shared_vars.js rename to chrome/browser/resources/extensions/shared_vars.ts
diff --git a/chrome/browser/resources/extensions/shortcut_util.js b/chrome/browser/resources/extensions/shortcut_util.ts similarity index 77% rename from chrome/browser/resources/extensions/shortcut_util.js rename to chrome/browser/resources/extensions/shortcut_util.ts index 6c20b5b..fb56f74 100644 --- a/chrome/browser/resources/extensions/shortcut_util.js +++ b/chrome/browser/resources/extensions/shortcut_util.ts
@@ -6,45 +6,41 @@ import {isChromeOS, isMac} from 'chrome://resources/js/cr.m.js'; -/** @enum {number} */ -export const Key = { - Comma: 188, - Del: 46, - Down: 40, - End: 35, - Escape: 27, - Home: 36, - Ins: 45, - Left: 37, - MediaNextTrack: 176, - MediaPlayPause: 179, - MediaPrevTrack: 177, - MediaStop: 178, - PageDown: 34, - PageUp: 33, - Period: 190, - Right: 39, - Space: 32, - Tab: 9, - Up: 38, -}; +export enum Key { + Comma = 188, + Del = 46, + Down = 40, + End = 35, + Escape = 27, + Home = 36, + Ins = 45, + Left = 37, + MediaNextTrack = 176, + MediaPlayPause = 179, + MediaPrevTrack = 177, + MediaStop = 178, + PageDown = 34, + PageUp = 33, + Period = 190, + Right = 39, + Space = 32, + Tab = 9, + Up = 38, +} /** * Enum for whether we require modifiers of a keycode. - * @enum {number} */ -const ModifierPolicy = { - NOT_ALLOWED: 0, - REQUIRED: 1 -}; +enum ModifierPolicy { + NOT_ALLOWED = 0, + REQUIRED = 1 +} /** * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack", * "MediaStop", "MediaPlayPause" are required to be used without any modifier. - * @param {number} keyCode - * @return {ModifierPolicy} */ -function getModifierPolicy(keyCode) { +function getModifierPolicy(keyCode: number): ModifierPolicy { switch (keyCode) { case Key.MediaNextTrack: case Key.MediaPlayPause: @@ -59,12 +55,11 @@ /** * Returns whether the keyboard event has a key modifier, which could affect * how it's handled. - * @param {!KeyboardEvent} e - * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be - * counted as modifier. - * @return {boolean} True if the event has any modifiers. + * @param countShiftAsModifier Whether the 'Shift' key should be counted as + * modifier. + * @return Whether the event has any modifiers. */ -function hasModifier(e, countShiftAsModifier) { +function hasModifier(e: KeyboardEvent, countShiftAsModifier: boolean): boolean { return e.ctrlKey || e.altKey || // Meta key is only relevant on Mac and CrOS, where we treat Command // and Search (respectively) as modifiers. @@ -74,15 +69,14 @@ /** * Checks whether the passed in |keyCode| is a valid extension command key. - * @param {number} keyCode - * @return {boolean} Whether the key is valid. + * @return Whether the key is valid. */ -export function isValidKeyCode(keyCode) { +export function isValidKeyCode(keyCode: number): boolean { if (keyCode === Key.Escape) { return false; } for (const k in Key) { - if (Key[k] === keyCode) { + if (Key[k as keyof typeof Key] === keyCode) { return true; } } @@ -93,10 +87,8 @@ /** * Converts a keystroke event to string form, ignoring invalid extension * commands. - * @param {!KeyboardEvent} e - * @return {string} The keystroke as a string. */ -export function keystrokeToString(e) { +export function keystrokeToString(e: KeyboardEvent): string { const output = []; // TODO(devlin): Should this be i18n'd? if (isMac && e.metaKey) { @@ -185,10 +177,10 @@ /** * Returns true if the event has valid modifiers. - * @param {!KeyboardEvent} e The keyboard event to consider. - * @return {boolean} True if the event is valid. + * @param e The keyboard event to consider. + * @return Wether the event is valid. */ -export function hasValidModifiers(e) { +export function hasValidModifiers(e: KeyboardEvent): boolean { switch (getModifierPolicy(e.keyCode)) { case ModifierPolicy.REQUIRED: return hasModifier(e, false);
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.html b/chrome/browser/resources/new_tab_page/modules/modules.html index bedde0a..c37b569 100644 --- a/chrome/browser/resources/new_tab_page/modules/modules.html +++ b/chrome/browser/resources/new_tab_page/modules/modules.html
@@ -10,6 +10,10 @@ ntp-module-wrapper + ntp-module-wrapper { margin-top: 16px; } + + #removeModuleToastMessage { + flex-grow: 1; + } </style> <template is="dom-repeat" items="[[modules_]]" id="modules" on-dom-change="onModulesLoaded_">
diff --git a/chrome/browser/resources/pdf/viewport.js b/chrome/browser/resources/pdf/viewport.js index 09774dc..e73048a 100644 --- a/chrome/browser/resources/pdf/viewport.js +++ b/chrome/browser/resources/pdf/viewport.js
@@ -570,7 +570,7 @@ * Sets the zoom of the viewport. * Same as setZoomInternal_ but for pinch zoom we have some more operations. * @param {number} scaleDelta The zoom delta. - * @param {!Point} center The pinch center in content coordinates. + * @param {!Point} center The pinch center in plugin coordinates. * @private */ setPinchZoomInternal_(scaleDelta, center) { @@ -580,11 +580,10 @@ 'Viewport.mightZoom_.'); this.internalZoom_ = this.clampZoom_(this.internalZoom_ * scaleDelta); - const newCenterInContent = this.frameToContent_(center); - const delta = { - x: (newCenterInContent.x - this.oldCenterInContent_.x), - y: (newCenterInContent.y - this.oldCenterInContent_.y) - }; + assert(this.oldCenterInContent_); + const delta = vectorDelta( + /** @type {!Point} */ (this.oldCenterInContent_), + this.pluginToContent_(center)); // Record the scroll position (relative to the pinch center). const zoom = this.getZoom(); @@ -599,18 +598,18 @@ } /** - * Converts a point from frame to content coordinates. - * @param {!Point} framePoint The frame coordinates. + * Converts a point from plugin to content coordinates. + * @param {!Point} pluginPoint The plugin coordinates. * @return {!Point} The content coordinates. * @private */ - frameToContent_(framePoint) { + pluginToContent_(pluginPoint) { // TODO(mcnee) Add a helper Point class to avoid duplicating operations // on plain {x,y} objects. const zoom = this.getZoom(); return { - x: (framePoint.x + this.position.x) / zoom, - y: (framePoint.y + this.position.y) / zoom + x: (pluginPoint.x + this.position.x) / zoom, + y: (pluginPoint.y + this.position.y) / zoom }; } @@ -1425,7 +1424,7 @@ y: this.window_.offsetHeight / 2 }; } else if (this.keepContentCentered_) { - this.oldCenterInContent_ = this.frameToContent_(this.pinchCenter_); + this.oldCenterInContent_ = this.pluginToContent_(this.pinchCenter_); this.keepContentCentered_ = false; } @@ -1481,7 +1480,7 @@ this.pinchPhase_ = PinchPhase.START; this.prevScale_ = 1; this.oldCenterInContent_ = - this.frameToContent_(this.frameToPluginCoordinate_(e.detail.center)); + this.pluginToContent_(this.frameToPluginCoordinate_(e.detail.center)); const needsScrollbars = this.documentNeedsScrollbars(this.getZoom()); this.keepContentCentered_ = !needsScrollbars.horizontal;
diff --git a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.html b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.html index 47f41d2..c94f4cb 100644 --- a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.html +++ b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.html
@@ -32,8 +32,7 @@ <option value="">$i18n{addAccountTitle}</option> </select> </div> - <div hidden$="[[!printServerScalingFlagEnabled_]]" - class="server-search-box-container"> + <div class="server-search-box-container"> <!-- TODO(crbug.com/1013408): Uses deprecated iron-dropdown. --> <cr-searchable-drop-down class="server-search-box-input" hidden$="[[!isSingleServerFetchingMode_]]"
diff --git a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.js b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.js index 6242ca3..4822040 100644 --- a/chrome/browser/resources/print_preview/ui/destination_dialog_cros.js +++ b/chrome/browser/resources/print_preview/ui/destination_dialog_cros.js
@@ -105,15 +105,6 @@ }, }, - /** @private */ - printServerScalingFlagEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('printServerScaling'); - }, - readOnly: true, - }, - /** @private {boolean} */ loadingServerPrinters_: { type: Boolean, @@ -151,9 +142,6 @@ /** @override */ ready() { - if (!this.printServerScalingFlagEnabled_) { - return; - } this.printServerStore_ = new PrintServerStore( (/** string */ eventName, /** !Function */ callback) => void this.addWebUIListener(eventName, callback)); @@ -362,7 +350,7 @@ * @private */ onPrintServerSelected_(printServerName) { - if (!this.printServerScalingFlagEnabled_ || !this.printServerStore_) { + if (!this.printServerStore_) { return; } this.printServerStore_.choosePrintServers(printServerName);
diff --git a/chrome/browser/resources/print_preview/ui/destination_list_item.js b/chrome/browser/resources/print_preview/ui/destination_list_item.js index 7a91ca67..8b5e7df 100644 --- a/chrome/browser/resources/print_preview/ui/destination_list_item.js +++ b/chrome/browser/resources/print_preview/ui/destination_list_item.js
@@ -96,15 +96,6 @@ type: Object, value: DestinationConfigStatus, }, - - /** @private */ - printerStatusFlagEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('showPrinterStatusInDialog'); - }, - readOnly: true, - }, // </if> }, @@ -209,8 +200,7 @@ } // <if expr="chromeos or lacros"> - if (this.printerStatusFlagEnabled_ && - this.destination.origin === DestinationOrigin.CROS) { + if (this.destination.origin === DestinationOrigin.CROS) { // Don't show status text when destination is configuring. if (this.configurationStatus_ !== DestinationConfigStatus.IDLE) { return ''; @@ -243,8 +233,7 @@ } // <if expr="chromeos or lacros"> - if (this.printerStatusFlagEnabled_ && - this.destination.origin === DestinationOrigin.CROS) { + if (this.destination.origin === DestinationOrigin.CROS) { return getPrinterStatusIcon( this.destination.printerStatusReason, this.destination.isEnterprisePrinter); @@ -261,20 +250,12 @@ * @private */ computeIsDestinationCrosLocal_: function() { - if (!this.printerStatusFlagEnabled_) { - return false; - } - return this.destination && this.destination.origin === DestinationOrigin.CROS; }, /** @private */ requestPrinterStatus_() { - if (!this.printerStatusFlagEnabled_) { - return; - } - // Requesting printer status only allowed for local CrOS printers. if (this.destination.origin !== DestinationOrigin.CROS) { return;
diff --git a/chrome/browser/resources/read_later/side_panel/bookmark_folder.html b/chrome/browser/resources/read_later/side_panel/bookmark_folder.html index 680db7f..1a8f441 100644 --- a/chrome/browser/resources/read_later/side_panel/bookmark_folder.html +++ b/chrome/browser/resources/read_later/side_panel/bookmark_folder.html
@@ -56,7 +56,9 @@ .title { grid-area: title; + overflow: hidden; padding: 0 10px; + text-overflow: ellipsis; } .bookmark {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_dialog.html b/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_dialog.html index 117bdbe..68d73dc 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_dialog.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/cellular_setup_dialog.html
@@ -25,6 +25,7 @@ } :host { + --cr-dialog-body-padding-horizontal: 24px; --cr-dialog-title-slot-padding-bottom: 0; --cr-dialog-title-slot-padding-end: 0; --cr-dialog-title-slot-padding-start: 0; @@ -32,10 +33,10 @@ } #header { - padding-bottom: 16px; - padding-inline-end: 20px; - padding-inline-start: 20px; - padding-top: 20px; + padding-bottom: 8px; + padding-inline-end: 24px; + padding-inline-start: 24px; + padding-top: 24px; } #title {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js index d52d266..6c13a2e 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
@@ -225,10 +225,13 @@ } const {pSimSlots, eSimSlots} = getSimSlotCount(deviceState); - if (this.isUpdatedCellularUiEnabled_ && eSimSlots > 0) { - // Do not show simInfo if |updatedCellularActivationUi| flag is enabled - // and if we are using an eSIM enabled device. - return false; + if (this.isUpdatedCellularUiEnabled_) { + if (eSimSlots > 0) { + // Do not show simInfo if |updatedCellularActivationUi| flag is enabled + // and if we are using an eSIM enabled device. + return false; + } + return this.simLocked_(deviceState); } return this.simLockedOrAbsent_(deviceState); }, @@ -277,6 +280,18 @@ if (deviceState.simAbsent) { return true; } + return this.simLocked_(deviceState); + }, + + /** + * @param {!OncMojo.DeviceStateProperties|undefined} deviceState + * @return {boolean} + * @private + */ + simLocked_(deviceState) { + if (!deviceState) { + return false; + } if (!deviceState.simLockStatus) { return false; } @@ -314,16 +329,21 @@ case mojom.NetworkType.kEthernet: case mojom.NetworkType.kVPN: return false; + case mojom.NetworkType.kTether: return true; + case mojom.NetworkType.kWiFi: return deviceState.deviceState !== mojom.DeviceStateType.kUninitialized; + case mojom.NetworkType.kCellular: - return (deviceState.deviceState !== - mojom.DeviceStateType.kUninitialized && - !this.simLockedOrAbsent_(deviceState)) || - (this.isUpdatedCellularUiEnabled_ && - this.simLockedOrAbsent_(deviceState)); + if (deviceState.deviceState === mojom.DeviceStateType.kUninitialized) { + return false; + } + + // Toggle should be shown as long as we are not also showing the UI for + // unlocking the SIM. + return !this.showSimInfo_(deviceState); } assertNotReached(); return false;
diff --git a/chrome/browser/resources/tab_search/BUILD.gn b/chrome/browser/resources/tab_search/BUILD.gn index 90c3c1b..a9e6db9 100644 --- a/chrome/browser/resources/tab_search/BUILD.gn +++ b/chrome/browser/resources/tab_search/BUILD.gn
@@ -16,6 +16,7 @@ preprocess_web_components_manifest = "preprocessed_gen_manifest.json" preprocess_fuse_manifest = "preprocessed_fuse_manifest.json" preprocess_mojo_manifest = "preprocessed_mojo_manifest.json" +preprocess_mojo_tab_groups_manifest = "preprocess_mojo_tab_groups.json" if (optimize_webui) { build_manifest = "build_manifest.json" @@ -31,12 +32,14 @@ "chrome://resources/js/cr.m.js", "chrome://resources/mojo/mojo/public/js/bindings.js", "chrome://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js", + "chrome://resources/mojo/mojo/public/mojom/base/token.mojom-webui.js", "fuse.js", ] deps = [ ":preprocess", ":preprocess_mojo", + ":preprocess_mojo_tab_groups", ":preprocess_web_components", "../../../../ui/webui/resources:preprocess", ] @@ -65,12 +68,14 @@ ":preprocess", ":preprocess_fuse", ":preprocess_mojo", + ":preprocess_mojo_tab_groups", ":preprocess_web_components", ] manifest_files = [ "$target_gen_dir/$preprocess_manifest", "$target_gen_dir/$preprocess_fuse_manifest", "$target_gen_dir/$preprocess_mojo_manifest", + "$target_gen_dir/$preprocess_mojo_tab_groups_manifest", "$target_gen_dir/$preprocess_web_components_manifest", ] } @@ -84,6 +89,7 @@ "bimap.js", "fuzzy_search.js", "tab_data.js", + "tab_group_color_helper.js", "tab_search.js", "tab_search_api_proxy.js", "title_item.js", @@ -98,6 +104,7 @@ in_files = [ "app.js", "infinite_list.js", + "tab_group_shared_vars.js", "tab_search_item.js", "tab_search_search_field.js", ] @@ -110,6 +117,14 @@ in_files = [ "fuse.basic.esm.min.js" ] } +preprocess_if_expr("preprocess_mojo_tab_groups") { + deps = [ "//components/tab_groups/public/mojom:mojo_bindings_webui_js" ] + in_folder = "$root_gen_dir/mojom-webui/components/tab_groups/public/mojom/" + out_folder = "$target_gen_dir/$preprocess_folder" + out_manifest = "$target_gen_dir/$preprocess_mojo_tab_groups_manifest" + in_files = [ "tab_group_types.mojom-webui.js" ] +} + preprocess_if_expr("preprocess_mojo") { deps = [ "//chrome/browser/ui/webui/tab_search:mojo_bindings_webui_js" ] in_folder = "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/tab_search/" @@ -143,6 +158,9 @@ "js_module_root=" + rebase_path( "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/tab_search", root_build_dir), + "js_module_root=" + rebase_path( + "$root_gen_dir/mojom-webui/components/tab_groups/public/mojom", + root_build_dir), ] deps = [ ":app", @@ -199,6 +217,10 @@ deps = [] } +js_library("tab_group_color_helper") { + deps = [ "//components/tab_groups/public/mojom:mojo_bindings_webui_js" ] +} + js_library("tab_search") { deps = [ ":app" ] } @@ -214,6 +236,7 @@ js_library("tab_search_item") { deps = [ ":tab_data", + ":tab_group_color_helper", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_elements:mouse_hoverable_mixin", "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m", @@ -237,6 +260,7 @@ js_files = [ "app.js", "infinite_list.js", + "tab_group_shared_vars.js", "tab_search_item.js", "tab_search_search_field.js", ]
diff --git a/chrome/browser/resources/tab_search/app.js b/chrome/browser/resources/tab_search/app.js index 31cbdc3..3360330d 100644 --- a/chrome/browser/resources/tab_search/app.js +++ b/chrome/browser/resources/tab_search/app.js
@@ -20,8 +20,8 @@ import {fuzzySearch} from './fuzzy_search.js'; import {InfiniteList, NO_SELECTION, selectorNavigationKeys} from './infinite_list.js'; -import {ariaLabel, TabData, TabItemType} from './tab_data.js'; -import {Tab, Window} from './tab_search.mojom-webui.js'; +import {ariaLabel, TabData, TabItemType, tokenToString} from './tab_data.js'; +import {Tab, TabGroup, Window} from './tab_search.mojom-webui.js'; import {TabSearchApiProxy, TabSearchApiProxyImpl} from './tab_search_api_proxy.js'; import {TitleItem} from './title_item.js'; @@ -126,6 +126,9 @@ /** @private {!Array<number>} */ this.listenerIds_ = []; + /** @private {!Map<string, !TabGroup>} */ + this.tabGroupsMap_ = new Map(); + /** @private {!Function} */ this.visibilityChangedListener_ = () => { // Refresh Tab Search's tab data when transitioning into a visible state. @@ -181,7 +184,8 @@ this.listenerIds_.push( callbackRouter.tabsChanged.addListener( profileData => this.tabsChanged_( - profileData.windows, profileData.recentlyClosedTabs)), + profileData.windows, profileData.recentlyClosedTabs, + profileData.tabGroups)), callbackRouter.tabUpdated.addListener(tab => this.onTabUpdated_(tab)), callbackRouter.tabsRemoved.addListener( tabIds => this.onTabsRemoved_(tabIds))); @@ -256,7 +260,9 @@ }); this.availableHeight_ = profileData.windows.find((t) => t.active).height; - this.tabsChanged_(profileData.windows, profileData.recentlyClosedTabs); + this.tabsChanged_( + profileData.windows, profileData.recentlyClosedTabs, + profileData.tabGroups); }); } @@ -269,7 +275,8 @@ for (let i = 0; i < this.openTabs_.length; ++i) { if (this.openTabs_[i].tab.tabId === updatedTab.tabId) { this.openTabs_[i] = this.tabData_( - updatedTab, this.openTabs_[i].inActiveWindow, TabItemType.OPEN); + updatedTab, this.openTabs_[i].inActiveWindow, TabItemType.OPEN, + this.tabGroupsMap_); this.updateFilteredTabs_(this.openTabs_, this.recentlyClosedTabs_); return; } @@ -408,15 +415,22 @@ /** * @param {!Array<!Window>} newOpenWindows * @param {!Array<!Tab>} recentlyClosedTabs + * @param {!Array<!TabGroup>} tabGroups * @private */ - tabsChanged_(newOpenWindows, recentlyClosedTabs) { + tabsChanged_(newOpenWindows, recentlyClosedTabs, tabGroups) { + this.tabGroupsMap_ = tabGroups.reduce((map, tabGroup) => { + map.set(tokenToString(tabGroup.id), tabGroup); + return map; + }, new Map()); this.openTabs_ = newOpenWindows.reduce( - (acc, {active, tabs}) => acc.concat( - tabs.map(tab => this.tabData_(tab, active, TabItemType.OPEN))), + (acc, {active, tabs}) => acc.concat(tabs.map( + tab => this.tabData_( + tab, active, TabItemType.OPEN, this.tabGroupsMap_))), []); this.recentlyClosedTabs_ = recentlyClosedTabs.map( - tab => this.tabData_(tab, false, TabItemType.RECENTLY_CLOSED)); + tab => this.tabData_( + tab, false, TabItemType.RECENTLY_CLOSED, this.tabGroupsMap_)); this.updateFilteredTabs_(this.openTabs_, this.recentlyClosedTabs_); // If there was no previously selected index, set the first item as @@ -556,10 +570,11 @@ * @param {!Tab} tab * @param {boolean} inActiveWindow * @param {!TabItemType} type + * @param {!Map<string, !TabGroup>} tabGroupsMap * @return {!TabData} * @private */ - tabData_(tab, inActiveWindow, type) { + tabData_(tab, inActiveWindow, type, tabGroupsMap) { const tabData = new TabData(); try { tabData.hostname = new URL(tab.url).hostname; @@ -570,6 +585,11 @@ } tabData.inActiveWindow = inActiveWindow; tabData.tab = tab; + + if (tab.groupId) { + tabData.tabGroup = tabGroupsMap.get(tokenToString(tab.groupId)); + } + tabData.type = type; tabData.a11yTypeText = loadTimeData.getStringF( type === TabItemType.OPEN ? 'a11yOpenTab' : 'a11yRecentlyClosedTab');
diff --git a/chrome/browser/resources/tab_search/fuzzy_search.js b/chrome/browser/resources/tab_search/fuzzy_search.js index 4f6c3b4..72c385a 100644 --- a/chrome/browser/resources/tab_search/fuzzy_search.js +++ b/chrome/browser/resources/tab_search/fuzzy_search.js
@@ -7,6 +7,9 @@ import Fuse from './fuse.js'; import {TabData} from './tab_data.js'; +// TODO(crbug.com/215325): Add support for fuzzy search matching on tab group +// title. + /** * @param {string} input * @param {!Array<!TabData>} records
diff --git a/chrome/browser/resources/tab_search/tab_data.js b/chrome/browser/resources/tab_search/tab_data.js index 410bb38..256c8dc 100644 --- a/chrome/browser/resources/tab_search/tab_data.js +++ b/chrome/browser/resources/tab_search/tab_data.js
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Tab} from './tab_search.mojom-webui.js'; +import {Token} from 'chrome://resources/mojo/mojo/public/mojom/base/token.mojom-webui.js'; + +import {Tab, TabGroup} from './tab_search.mojom-webui.js'; /** @enum {number} */ export const TabItemType = { @@ -37,14 +39,28 @@ /** @type {string} */ this.a11yTypeText; + + /** @type {?TabGroup} */ + this.tabGroup; } } /** + * Converts a token to a string by combining the high and low values as strings + * with a hashtag as the separator. + * @param {!Token} token + * @return {string} + */ +export function tokenToString(token) { + return `${token.high.toString()}#${token.low.toString()}`; +} + +/** * @param {!TabData} tabData * @return {string} */ export function ariaLabel(tabData) { - return `${tabData.tab.title} ${tabData.hostname} ${ + const groupTitleOrEmpty = tabData.tabGroup ? tabData.tabGroup.title : ''; + return `${tabData.tab.title} ${groupTitleOrEmpty} ${tabData.hostname} ${ tabData.tab.lastActiveElapsedText} ${tabData.a11yTypeText}`; }
diff --git a/chrome/browser/resources/tab_search/tab_group_color_helper.js b/chrome/browser/resources/tab_search/tab_group_color_helper.js new file mode 100644 index 0000000..a880bd6a --- /dev/null +++ b/chrome/browser/resources/tab_search/tab_group_color_helper.js
@@ -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. + +import './tab_group_shared_vars.js'; + +import {Color} from './tab_group_types.mojom-webui.js'; + +/** @type Map<Color, string> */ +const colorMap = new Map([ + [Color.kGrey, 'grey'], + [Color.kBlue, 'blue'], + [Color.kRed, 'red'], + [Color.kYellow, 'yellow'], + [Color.kGreen, 'green'], + [Color.kPink, 'pink'], + [Color.kPurple, 'purple'], + [Color.kCyan, 'cyan'], +]); + +/** + * @param {Color} color + * @return {string} + * @throws {Error} + */ +export function colorName(color) { + if (!colorMap.has(color)) { + throw Error('Undefined color id'); + } + + return colorMap.get(color); +}
diff --git a/chrome/browser/resources/tab_search/tab_group_shared_vars.html b/chrome/browser/resources/tab_search/tab_group_shared_vars.html new file mode 100644 index 0000000..9f09068 --- /dev/null +++ b/chrome/browser/resources/tab_search/tab_group_shared_vars.html
@@ -0,0 +1,61 @@ +<custom-style> + <style> + /* + * TODO(romanarora): Move to cr_elements folder when another component needs + * to reference the file. + */ + + /* Matches colors specified in ThemeHelper::GetTabGroupColors. */ + html { + /* TODO(romanarora): Consider moving colors to shared_vars_css.html. Only + * adds colors not already present in shared_vars_css.html. + */ + --google-blue-300-rgb: 123, 170, 247; + --google-blue-300: rgb(var(--google-blue-300-rgb)); + --google-cyan-300-rgb: 120, 217, 236; /* #78d9ec */ + --google-cyan-300: rgb(var(--google-cyan-300-rgb)); + --google-cyan-900-rgb: 0, 123, 131; /* #007b83 */ + --google-cyan-900: rgb(var(--google-cyan-900-rgb)); + --google-green-300-rgb: 87, 187, 138; /* #57bb8a */ + --google-green-300: rgb(var(--google-green-300-rgb)); + --google-green-600-rgb: 30, 142, 62; /* #1e8e3e */ + --google-green-600: rgb(var(--google-green-600-rgb)); + --google-pink-300-rgb: 255, 139, 203; /* #ff8bcb */ + --google-pink-300: rgb(var(--google-pink-300-rgb)); + --google-pink-700-rgb: 208, 24, 132; /* #d01884 */ + --google-pink-700: rgb(var(--google-pink-700-rgb)); + --google-purple-200-rgb: 215, 174, 251; /* #d7aefb */ + --google-purple-200: rgb(var(--google-purple-200-rgb)); + --google-purple-600-rgb: 147, 52, 230; /* #9334e6 */ + --google-purple-600: rgb(var(--google-purple-600-rgb)); + --google-red-300-rgb: 230, 124, 115; /* #e67c73 */ + --google-red-300: rgb(var(--google-red-300-rgb)); + --google-yellow-300-rgb: 247, 203, 77; /* #f7cb4d */ + --google-yellow-300: rgb(var(--google-yellow-300-rgb)); + --google-yellow-900-rgb: 227, 116, 0; /* #e37400 */ + --google-yellow-900: rgb(var(--google-yellow-900-rgb)); + + --tab-group-color-grey: var(--google-grey-700); + --tab-group-color-blue: var(--google-blue-600); + --tab-group-color-red: var(--google-red-600); + --tab-group-color-yellow: var(--google-yellow-900); + --tab-group-color-green: var(--google-green-600); + --tab-group-color-pink: var(--google-pink-700); + --tab-group-color-purple: var(--google-purple-600); + --tab-group-color-cyan: var(--google-cyan-900); + } + + @media (prefers-color-scheme: dark) { + html { + --tab-group-color-grey: var(--google-grey-400); + --tab-group-color-blue: var(--google-blue-300); + --tab-group-color-red: var(--google-red-300); + --tab-group-color-yellow: var(--google-yellow-300); + --tab-group-color-green: var(--google-green-300); + --tab-group-color-pink: var(--google-pink-300); + --tab-group-color-purple: var(--google-purple-200); + --tab-group-color-cyan: var(--google-cyan-300); + } + } + </style> +</custom-style>
diff --git a/chrome/browser/resources/tab_search/tab_group_shared_vars.js b/chrome/browser/resources/tab_search/tab_group_shared_vars.js new file mode 100644 index 0000000..2bd30f5 --- /dev/null +++ b/chrome/browser/resources/tab_search/tab_group_shared_vars.js
@@ -0,0 +1,7 @@ +// 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. + +const $_documentContainer = document.createElement('template'); +$_documentContainer.innerHTML = `{__html_template__}`; +document.head.appendChild($_documentContainer.content);
diff --git a/chrome/browser/resources/tab_search/tab_search.js b/chrome/browser/resources/tab_search/tab_search.js index ea25330..6a3289a 100644 --- a/chrome/browser/resources/tab_search/tab_search.js +++ b/chrome/browser/resources/tab_search/tab_search.js
@@ -9,7 +9,8 @@ export {fuzzySearch} from './fuzzy_search.js'; export {InfiniteList} from './infinite_list.js'; export {TabData, TabItemType} from './tab_data.js'; -export {PageCallbackRouter, PageRemote, ProfileData, Tab} from './tab_search.mojom-webui.js'; +export {Color as TabGroupColor} from './tab_group_types.mojom-webui.js'; +export {PageCallbackRouter, PageRemote, ProfileData, Tab, TabGroup} from './tab_search.mojom-webui.js'; export {TabSearchApiProxy, TabSearchApiProxyImpl} from './tab_search_api_proxy.js'; export {TabSearchItem} from './tab_search_item.js'; export {TabSearchSearchField} from './tab_search_search_field.js';
diff --git a/chrome/browser/resources/tab_search/tab_search_item.html b/chrome/browser/resources/tab_search/tab_search_item.html index 7c32528..7b978d9 100644 --- a/chrome/browser/resources/tab_search/tab_search_item.html +++ b/chrome/browser/resources/tab_search/tab_search_item.html
@@ -45,6 +45,7 @@ user-select: none; } + #groupTitle, #primaryText, #secondaryText { overflow: hidden; @@ -59,6 +60,7 @@ } #secondaryContainer { + align-items: center; color: var(--cr-secondary-text-color); display: flex; font-size: var(--mwb-secondary-text-font-size); @@ -74,7 +76,7 @@ position: fixed; } - #separator { + .separator { margin-inline-end: 4px; margin-inline-start: 4px; } @@ -89,6 +91,17 @@ .search-highlight-hit { font-weight: bold; } + + #groupSvg { + flex-shrink: 0; + height: 8px; + margin-inline-end: 6px; + width: 8px; + } + + #groupDot { + fill: var(--group-dot-color); + } </style> <div class="favicon" style="background-image:[[faviconUrl_(data.tab)]]"></div> @@ -96,8 +109,16 @@ <div class="text-container" aria-hidden="true"> <div id="primaryText" title="[[data.tab.title]]"></div> <div id="secondaryContainer"> + <template is="dom-if" if="[[data.tabGroup]]"> + <svg id="groupSvg" viewBox="-5 -5 10 10" + xmlns="http://www.w3.org/2000/svg"> + <circle id= "groupDot" cx="0" cy="0" r="4"> + </svg> + <div id="groupTitle">[[data.tabGroup.title]]</div> + <div class="separator">•</div> + </template> <div id="secondaryText"></div> - <div id="separator" hidden="[[!data.hostname]]">•</div> + <div class="separator" hidden="[[!data.hostname]]">•</div> <div id="secondaryTimestamp"> [[data.tab.lastActiveElapsedText]] </div>
diff --git a/chrome/browser/resources/tab_search/tab_search_item.js b/chrome/browser/resources/tab_search/tab_search_item.js index bdb93fd..a2c9a4c 100644 --- a/chrome/browser/resources/tab_search/tab_search_item.js +++ b/chrome/browser/resources/tab_search/tab_search_item.js
@@ -14,8 +14,8 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {highlight} from 'chrome://resources/js/search_highlight_utils.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - import {ariaLabel, TabData, TabItemType} from './tab_data.js'; +import {colorName} from './tab_group_color_helper.js'; import {Tab} from './tab_search.mojom-webui.js'; /** @@ -84,9 +84,7 @@ tab.isDefaultFavicon ? 'chrome://newtab' : tab.url, false); } - /** - * @private - */ + /** @private */ dataChanged_() { this.highlightText_( /** @type {!HTMLElement} */ (this.$.primaryText), this.data.tab.title, @@ -110,13 +108,19 @@ .prepend(document.createTextNode('chrome://')); secondaryLabel = `chrome://${secondaryLabel}`; } + + if (this.data.tabGroup) { + this.style.setProperty( + '--group-dot-color', + `var(--tab-group-color-${colorName(this.data.tabGroup.color)})`); + } } /** - * * @param {!HTMLElement} container * @param {string} text * @param {!Array<!{start:number, length:number}>|undefined} ranges + * @private */ highlightText_(container, text, ranges) { container.textContent = '';
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc index 6e14228..ebf1754 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.cc
@@ -218,9 +218,12 @@ // Reports the SwReporter run time with UMA both as reported by the tool via // the registry and as measured by |ReporterRunner|. - void ReportRuntime(const base::TimeDelta& reporter_running_time) const { + void ReportRuntime(const base::TimeDelta& reporter_running_time, + const base::TimeDelta& running_time_without_sleep) const { RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome", reporter_running_time); + RecordLongTimesHistogram("SoftwareReporter.RunningTimeWithoutSleep", + running_time_without_sleep); // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE. base::win::RegKey reporter_key; @@ -468,6 +471,10 @@ } private: + // The type returned by QueryUnbiasedInterruptTime, which does not include + // time spent in sleep or hibernation. + using TimestampWithoutSleep = ULONGLONG; + // Keeps track of last and upcoming reporter runs and logs uploading. // // Periodic runs are allowed to start if the last time the reporter ran was @@ -554,11 +561,15 @@ base::TaskRunner* task_runner = g_testing_delegate_ ? g_testing_delegate_->BlockingTaskRunner() : blocking_task_runner_.get(); + + TimestampWithoutSleep now_without_sleep; + ::QueryUnbiasedInterruptTime(&now_without_sleep); + auto launch_and_wait = base::BindOnce(&LaunchAndWaitForExit, next_invocation); auto reporter_done = base::BindOnce(&ReporterRunner::ReporterDone, base::Unretained(this), - Now(), next_invocation); + Now(), now_without_sleep, next_invocation); base::PostTaskAndReplyWithResult(task_runner, FROM_HERE, std::move(launch_and_wait), std::move(reporter_done)); @@ -568,6 +579,7 @@ // has completed. This is run as a task posted from an interruptible worker // thread so should be resilient to unexpected shutdown. void ReporterDone(const base::Time& reporter_start_time, + TimestampWithoutSleep start_time_without_sleep, SwReporterInvocation finished_invocation, int exit_code) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -590,9 +602,18 @@ return; } + TimestampWithoutSleep now_without_sleep; + ::QueryUnbiasedInterruptTime(&now_without_sleep); + base::Time now = Now(); base::TimeDelta reporter_running_time = now - reporter_start_time; + // QueryUnbiasedInterruptTime returns units of 100 nanoseconds. See + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttime + base::TimeDelta running_time_without_sleep = + base::TimeDelta::FromNanoseconds( + 100 * (now_without_sleep - start_time_without_sleep)); + // Tries to run the next invocation in the queue. if (!invocations_.container().empty()) { // If there are other invocations to start, then we shouldn't finalize @@ -616,7 +637,7 @@ local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, now.ToInternalValue()); } - uma.ReportRuntime(reporter_running_time); + uma.ReportRuntime(reporter_running_time, running_time_without_sleep); uma.ReportMemoryUsage(); if (finished_invocation.reporter_logs_upload_enabled()) uma.RecordLogsUploadResult();
diff --git a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc index 78a18b93..29319ea 100644 --- a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc +++ b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
@@ -181,7 +181,7 @@ // Assigns a browser window to all desks. IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS, - DISABLED_PRE_RestoreAllDesksBrowserWindow) { + PRE_RestoreAllDesksBrowserWindow) { // Create two desks so we have three in total. ash::AutotestDesksApi().CreateNewDesk(); ash::AutotestDesksApi().CreateNewDesk(); @@ -212,7 +212,7 @@ // Verifies that the visible on all desks browser window is restore properly. IN_PROC_BROWSER_TEST_F(SessionRestoreTestChromeOS, - DISABLED_RestoreAllDesksBrowserWindow) { + RestoreAllDesksBrowserWindow) { // There should be two browsers restored, the default browser and the all // desks browser. auto* browser_list = BrowserList::GetInstance();
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeCoordinator.java index 772c98a..ee9effa 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeCoordinator.java
@@ -7,6 +7,8 @@ import android.app.Activity; import android.app.FragmentManager; +import org.chromium.ui.base.AndroidPermissionDelegate; + /** * Creates and represents the QrCode main UI. */ @@ -14,8 +16,15 @@ private final QrCodeDialog mDialog; private final FragmentManager mFragmentManager; - public QrCodeCoordinator(Activity activity, String url) { - mDialog = QrCodeDialog.newInstance(url); + /** + * Constructor. + * @param activity The android activity. + * @param url the url to be shared. + * @param windowAndroid the AndroidPermissionDelegate to access system permissions. + */ + public QrCodeCoordinator( + Activity activity, String url, AndroidPermissionDelegate windowAndroid) { + mDialog = QrCodeDialog.newInstance(url, windowAndroid); mFragmentManager = activity.getFragmentManager(); }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java index 775bbd62..93a5fd8c 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/QrCodeDialog.java
@@ -18,6 +18,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.share.qrcode.scan_tab.QrCodeScanCoordinator; import org.chromium.chrome.browser.share.qrcode.share_tab.QrCodeShareCoordinator; +import org.chromium.ui.base.AndroidPermissionDelegate; import org.chromium.ui.widget.ChromeImageButton; import java.util.ArrayList; @@ -29,17 +30,21 @@ // Used to pass the URL in the bundle. public static String URL_KEY = "url_key"; + private AndroidPermissionDelegate mWindowAndroid; private ArrayList<QrCodeDialogTab> mTabs; private TabLayoutPageListener mTabLayoutPageListener; /** * Create a new instance of {@link QrCodeDialog} and set the URL. + * @param windowAndroid The AndroidPermissionDelegate to be query for download permissions. */ - static QrCodeDialog newInstance(String url) { + static QrCodeDialog newInstance(String url, AndroidPermissionDelegate windowAndroid) { + assert windowAndroid != null; QrCodeDialog qrCodeDialog = new QrCodeDialog(); Bundle args = new Bundle(); args.putString(URL_KEY, url); qrCodeDialog.setArguments(args); + qrCodeDialog.setAndroidPermissionDelegate(windowAndroid); return qrCodeDialog; } @@ -71,6 +76,15 @@ tab.onDestroy(); } mTabs.clear(); + mWindowAndroid = null; + } + + /** + * Setter for the current WindowAndroid. + * @param windowAndroid The windowAndroid to set. + */ + public void setAndroidPermissionDelegate(AndroidPermissionDelegate windowAndroid) { + mWindowAndroid = windowAndroid; } private View getDialogView() { @@ -99,7 +113,7 @@ Context context = getActivity(); QrCodeShareCoordinator shareCoordinator = new QrCodeShareCoordinator( - context, this::dismiss, getArguments().getString(URL_KEY)); + context, this::dismiss, getArguments().getString(URL_KEY), mWindowAndroid); QrCodeScanCoordinator scanCoordinator = new QrCodeScanCoordinator(context, this::dismiss); mTabs = new ArrayList<>();
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareCoordinator.java index 641f50a..a59d476 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareCoordinator.java
@@ -9,6 +9,7 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.browser.share.qrcode.QrCodeDialogTab; +import org.chromium.ui.base.AndroidPermissionDelegate; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; @@ -19,9 +20,11 @@ private final QrCodeShareView mShareView; private final QrCodeShareMediator mMediator; - public QrCodeShareCoordinator(Context context, Runnable closeDialog, String url) { + public QrCodeShareCoordinator(Context context, Runnable closeDialog, String url, + AndroidPermissionDelegate windowAndroid) { PropertyModel shareViewModel = new PropertyModel(QrCodeShareViewProperties.ALL_KEYS); - mMediator = new QrCodeShareMediator(context, shareViewModel, closeDialog, url); + mMediator = + new QrCodeShareMediator(context, shareViewModel, closeDialog, url, windowAndroid); mShareView = new QrCodeShareView(context, mMediator::downloadQrCode); PropertyModelChangeProcessor.create( shareViewModel, mShareView, new QrCodeShareViewBinder());
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareMediator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareMediator.java index c19de19..f2e0d26 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareMediator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/qrcode/share_tab/QrCodeShareMediator.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.share.qrcode.share_tab; import android.Manifest.permission; -import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Bitmap; @@ -24,12 +23,9 @@ import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.share.BitmapDownloadRequest; import org.chromium.chrome.browser.share.qrcode.QRCodeGenerationRequest; -import org.chromium.ui.base.ActivityAndroidPermissionDelegate; import org.chromium.ui.base.AndroidPermissionDelegate; import org.chromium.ui.modelutil.PropertyModel; -import java.lang.ref.WeakReference; - /** * QrCodeShareMediator is in charge of calculating and setting values for QrCodeShareViewProperties. */ @@ -53,17 +49,17 @@ * @param propertyModel The property model to use to communicate with views. * @param closeDialog The {@link Runnable} to close the dialog. * @param url The url to create the QRCode. + * @param permissionDelegate The delegate to help with downloading QRCode. */ - QrCodeShareMediator( - Context context, PropertyModel propertyModel, Runnable closeDialog, String url) { + QrCodeShareMediator(Context context, PropertyModel propertyModel, Runnable closeDialog, + String url, AndroidPermissionDelegate permissionDelegate) { mContext = context; mPropertyModel = propertyModel; mCloseDialog = closeDialog; mUrl = url; ChromeBrowserInitializer.getInstance().runNowOrAfterFullBrowserStarted( () -> refreshQrCode(mUrl)); - mPermissionDelegate = new ActivityAndroidPermissionDelegate( - new WeakReference<Activity>((Activity) mContext)); + mPermissionDelegate = permissionDelegate; updatePermissionSettings(); } @@ -105,9 +101,8 @@ logDownload(); Bitmap qrcodeBitmap = mPropertyModel.get(QrCodeShareViewProperties.QRCODE_BITMAP); if (qrcodeBitmap != null && !mIsDownloadInProgress) { - // TODO(crbug/1209228): Pass the window android. DownloadController.requestFileAccessPermission( - null, this::finishDownloadWithPermission); + mPermissionDelegate, this::finishDownloadWithPermission); return; } }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java index 6e13206..d0779d0 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
@@ -410,7 +410,8 @@ .setIcon(R.drawable.qr_code, R.string.qr_code_share_icon_label) .setFeatureNameForMetrics("SharingHubAndroid.QRCodeSelected") .setOnClickCallback((view) -> { - QrCodeCoordinator qrCodeCoordinator = new QrCodeCoordinator(mActivity, mUrl); + QrCodeCoordinator qrCodeCoordinator = new QrCodeCoordinator( + mActivity, mUrl, mTabProvider.get().getWindowAndroid()); qrCodeCoordinator.show(); }) .build();
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc index eb582d3..22f7d14f 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -18,7 +18,6 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" -#include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" @@ -42,16 +41,9 @@ #include "chrome/common/themes/autogenerated_theme_util.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/common/password_manager_ui.h" -#include "components/policy/core/browser/browser_policy_connector.h" -#include "components/policy/core/common/policy_map.h" -#include "components/policy/core/common/policy_namespace.h" -#include "components/policy/core/common/policy_service.h" -#include "components/policy/policy_constants.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" -#include "components/signin/public/base/signin_pref_names.h" -#include "components/signin/public/identity_manager/accounts_mutator.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "google_apis/gaia/gaia_auth_util.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -182,16 +174,6 @@ // interception is missed. return SigninInterceptionHeuristicOutcome::kAbortSyncSignin; } - - // If the email is an not an customer email and enterprise profile separation - // is mandatory, return `absl::nullopt` so that more information on the - // account is fetched. - if (!policy::BrowserPolicyConnector::IsNonEnterpriseUser(email) && - profile_->GetPrefs()->HasPrefPath( - prefs::kManagedAccountsSigninRestriction)) { - return absl::nullopt; - } - if (!is_new_account) { // Do not intercept reauth. return SigninInterceptionHeuristicOutcome::kAbortAccountNotNew; @@ -289,7 +271,6 @@ &entry); account_id_ = account_id; is_interception_in_progress_ = true; - new_account_interception_ = is_new_account; Observe(web_contents); if (heuristic_outcome) { @@ -334,13 +315,9 @@ CoreAccountId account_id, content::WebContents* intercepted_contents, std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle, - bool managed_account_interception, bool is_new_profile) { DCHECK(!session_startup_helper_); - DCHECK(bubble_handle || managed_account_interception); - DCHECK_EQ(managed_account_interception, !bubble_handle) - << "There should be no handle for managed accout interception"; - managed_account_interception_ = managed_account_interception; + DCHECK(bubble_handle); interception_bubble_handle_ = std::move(bubble_handle); session_startup_helper_ = std::make_unique<DiceInterceptedSessionStartupHelper>( @@ -364,9 +341,6 @@ on_account_info_update_timeout_.Cancel(); is_interception_in_progress_ = false; account_id_ = CoreAccountId(); - new_account_interception_ = false; - managed_account_interception_ = false; - intercepted_account_management_accepted_ = false; dice_signed_in_profile_creator_.reset(); was_interception_ui_displayed_ = false; account_info_fetch_start_time_ = base::TimeTicks(); @@ -392,34 +366,6 @@ return nullptr; } -bool DiceWebSigninInterceptor::ShouldEnforceEnterpriseProfileSeparation( - const AccountInfo& intercepted_account_info) const { - DCHECK(intercepted_account_info.IsValid()); - - CoreAccountInfo primary_core_account_info = - identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); - // In case of re-auth, do not show the enterprise separation dialog if the - // user already consented to enterprise management. - if (!new_account_interception_ && primary_core_account_info.account_id == - intercepted_account_info.account_id) { - return base::FeatureList::IsEnabled(kAccountPoliciesLoadedWithoutSync) && - !profile_->GetPrefs()->GetBoolean( - prefs::kUserAcceptedAccountManagement); - } - - std::string account_restriction = - profile_->GetPrefs()->GetString(prefs::kManagedAccountsSigninRestriction); - if ((!account_restriction.empty() && - profile_->GetPrefs()->GetBoolean( - prefs::kManagedAccountsSigninRestrictionScopeMachine)) || - account_restriction == "primary_account_strict") { - return intercepted_account_info.IsManaged(); - } - - // TODO(crbug/1163117) Look for the policy value for the intercepted account. - return false; -} - bool DiceWebSigninInterceptor::ShouldShowEnterpriseBubble( const AccountInfo& intercepted_account_info) const { DCHECK(intercepted_account_info.IsValid()); @@ -478,47 +424,6 @@ absl::optional<SigninInterceptionType> interception_type; - ProfileAttributesEntry* entry = - g_browser_process->profile_manager() - ->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(profile_->GetPath()); - SkColor profile_color = GenerateNewProfileColor(entry).color; - - if (ShouldEnforceEnterpriseProfileSeparation(info)) { - // TODO (crbug/1163117): Create a new SigninInterceptionType and use - // interception_bubble_handle_. - DCHECK(base::FeatureList::IsEnabled(kAccountPoliciesLoadedWithoutSync) || - !profile_->GetPrefs() - ->GetString(prefs::kManagedAccountsSigninRestriction) - .empty()); - managed_account_interception_ = true; - // Immediately switch to an already existing profile. - const ProfileAttributesEntry* switch_to_entry = - ShouldShowProfileSwitchBubble(info.email, - &g_browser_process->profile_manager() - ->GetProfileAttributesStorage()); - if (switch_to_entry) { - // TODO (crbug/1163117): There should be a UI notifying the user of the - // profile switch. - RecordSigninInterceptionHeuristicOutcome( - SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch); - OnProfileSwitchChoice(info.email, switch_to_entry->GetPath(), - SigninInterceptionResult::kAccepted); - } else { - RecordSigninInterceptionHeuristicOutcome( - SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); - Browser* browser = chrome::FindBrowserWithProfile(profile_); - DCHECK(browser); - delegate_->ShowEnterpriseProfileInterceptionDialog( - info.email, - base::BindOnce( - &DiceWebSigninInterceptor::OnEnterpriseProfileCreationResult, - base::Unretained(this), info, profile_color), - browser); - } - return; - } if (ShouldShowEnterpriseBubble(info)) interception_type = SigninInterceptionType::kEnterprise; else if (ShouldShowMultiUserBubble(info)) @@ -532,6 +437,11 @@ return; } + ProfileAttributesEntry* entry = + g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(profile_->GetPath()); + SkColor profile_color = GenerateNewProfileColor(entry).color; auto guest_option_availability = GetGuestOptionAvailablity(); Delegate::BubbleParameters bubble_parameters{ *interception_type, info, GetPrimaryAccountInfo(identity_manager_), @@ -568,7 +478,7 @@ return; } - DCHECK(interception_bubble_handle_ || managed_account_interception_); + DCHECK(interception_bubble_handle_); profile_creation_start_time_ = base::TimeTicks::Now(); std::u16string profile_name; profile_name = profiles::GetDefaultNameForNewSignedInProfile(account_info); @@ -595,7 +505,7 @@ return; } - DCHECK(interception_bubble_handle_ || managed_account_interception_); + DCHECK(interception_bubble_handle_); DCHECK(!dice_signed_in_profile_creator_); profile_creation_start_time_ = base::TimeTicks::Now(); // Unretained is fine because the profile creator is owned by this. @@ -639,49 +549,17 @@ base::TimeTicks::Now() - profile_creation_start_time_); } - new_profile->GetPrefs()->SetBoolean(prefs::kUserAcceptedAccountManagement, - intercepted_account_management_accepted_); - // Work is done in this profile, the flow continues in the // DiceWebSigninInterceptor that is attached to the new profile. DiceWebSigninInterceptorFactory::GetForProfile(new_profile) ->CreateBrowserAfterSigninInterception( account_id_, web_contents(), std::move(interception_bubble_handle_), - managed_account_interception_, is_new_profile); + is_new_profile); Reset(); } -void DiceWebSigninInterceptor::OnEnterpriseProfileCreationResult( - const AccountInfo& account_info, - SkColor profile_color, - bool create) { - intercepted_account_management_accepted_ = create; - if (create) { - // In case of a reauth if there was no consent for management, do not create - // a new profile. - if (!new_account_interception_ && - GetPrimaryAccountInfo(identity_manager_).account_id == - account_info.account_id) { - profile_->GetPrefs()->SetBoolean( - prefs::kUserAcceptedAccountManagement, - intercepted_account_management_accepted_); - } else { - OnProfileCreationChoice(account_info, profile_color, - SigninInterceptionResult::kAccepted); - } - } else { - OnProfileCreationChoice(account_info, profile_color, - SigninInterceptionResult::kDeclined); - auto* accounts_mutator = identity_manager_->GetAccountsMutator(); - accounts_mutator->RemoveAccount( - account_info.account_id, - signin_metrics::SourceForRefreshTokenOperation:: - kDiceTurnOnSyncHelper_Abort); - } -} - void DiceWebSigninInterceptor::OnNewBrowserCreated(bool is_new_profile) { - DCHECK(interception_bubble_handle_ || managed_account_interception_); + DCHECK(interception_bubble_handle_); interception_bubble_handle_.reset(); // Close the bubble now. session_startup_helper_.reset();
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h index 86fed40..22978f7 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.h +++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -13,7 +13,6 @@ #include "base/gtest_prod_util.h" #include "base/scoped_observation.h" #include "base/time/time.h" -#include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.h" #include "components/keyed_service/core/keyed_service.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/web_contents_observer.h" @@ -82,11 +81,7 @@ // Signin interception is disabled by the SigninInterceptionEnabled policy. kAbortInterceptionDisabled = 15, - // Interception succeeded when enteprise account separation is mandatory. - kInterceptEnterpriseForced = 16, - kInterceptEnterpriseForcedProfileSwitch = 17, - - kMaxValue = kInterceptEnterpriseForcedProfileSwitch, + kMaxValue = kAbortInterceptionDisabled, }; // User selection in the interception bubble. @@ -177,14 +172,6 @@ const BubbleParameters& bubble_parameters, base::OnceCallback<void(SigninInterceptionResult)> callback) = 0; - // Shows the enterprise profile confirmation dialog to notify the user that - // a managed profile will be created or that their account needs a new - // profile to be created. - virtual void ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) = 0; - // Shows the profile customization bubble. virtual void ShowProfileCustomizationBubble(Browser* browser) = 0; }; @@ -224,7 +211,6 @@ content::WebContents* intercepted_contents, std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle, - bool managed_account_interception, bool is_new_profile); // Returns the outcome of the interception heuristic. @@ -258,15 +244,7 @@ ShouldShowEnterpriseBubbleWithoutUPA); FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, ShouldShowMultiUserBubble); - FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, - ShouldEnforceEnterpriseProfileSeparation); - FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, - ShouldEnforceEnterpriseProfileSeparationWithoutUPA); - FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, - ShouldEnforceEnterpriseProfileSeparationReauth); FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, PersistentHash); - FRIEND_TEST_ALL_PREFIXES(DiceWebSigninInterceptorTest, - EnforceManagedAccountAsPrimary); // Cancels any current signin interception and resets the interceptor to its // initial state. @@ -276,8 +254,6 @@ const ProfileAttributesEntry* ShouldShowProfileSwitchBubble( const std::string& intercepted_email, ProfileAttributesStorage* profile_attribute_storage) const; - bool ShouldEnforceEnterpriseProfileSeparation( - const AccountInfo& intercepted_account_info) const; bool ShouldShowEnterpriseBubble( const AccountInfo& intercepted_account_info) const; bool ShouldShowMultiUserBubble( @@ -305,13 +281,6 @@ void OnNewSignedInProfileCreated(absl::optional<SkColor> profile_color, Profile* new_profile); - // Called after the user choses whether the session should continue in a new - // work profile or not. If the user choses not to continue in a work profile, - // the account is signed out. - void OnEnterpriseProfileCreationResult(const AccountInfo& account_info, - SkColor profile_color, - bool create); - // Called when the new browser is created after interception. Passed as // callback to `session_startup_helper_`. void OnNewBrowserCreated(bool is_new_profile); @@ -346,9 +315,6 @@ // Members below are related to the interception in progress. bool is_interception_in_progress_ = false; CoreAccountId account_id_; - bool new_account_interception_ = false; - bool managed_account_interception_ = false; - bool intercepted_account_management_accepted_ = false; base::ScopedObservation<signin::IdentityManager, signin::IdentityManager::Observer> account_info_update_observation_{this};
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc index df5525fe..feefd78a 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -32,13 +32,11 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_features.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/profile_waiter.h" #include "chrome/test/base/ui_test_utils.h" #include "components/account_id/account_id.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "components/prefs/pref_service.h" #include "components/signin/public/identity_manager/accounts_mutator.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_environment.h" @@ -100,13 +98,6 @@ return bubble_handle; } - void ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) override { - std::move(callback).Run(expected_enteprise_confirmation_result_); - } - void ShowProfileCustomizationBubble(Browser* browser) override { EXPECT_FALSE(customized_browser_) << "Customization must be shown only once."; @@ -124,10 +115,6 @@ expected_interception_result_ = result; } - void set_expected_enteprise_confirmation_result(bool result) { - expected_enteprise_confirmation_result_ = result; - } - bool intercept_bubble_shown() const { return weak_bubble_handle_.get(); } bool intercept_bubble_destroyed() const { @@ -140,7 +127,6 @@ DiceWebSigninInterceptor::SigninInterceptionType::kMultiUser; SigninInterceptionResult expected_interception_result_ = SigninInterceptionResult::kAccepted; - bool expected_enteprise_confirmation_result_ = false; base::WeakPtr<FakeBubbleHandle> weak_bubble_handle_; }; @@ -186,22 +172,15 @@ SigninInterceptionHeuristicOutcome outcome, bool intercept_to_guest = false) { int profile_switch_count = - outcome == SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch || - outcome == SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch + outcome == SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch ? 1 : 0; int profile_creation_count = 1 - profile_switch_count; - int fetched_account_count = - outcome == SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch - ? 1 - : profile_creation_count; histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", outcome, 1); histogram_tester.ExpectTotalCount("Signin.Intercept.AccountInfoFetchDuration", - fetched_account_count); + profile_creation_count); histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileCreationDuration", profile_creation_count); histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileSwitchDuration", @@ -261,9 +240,6 @@ return interceptor_delegate; } - protected: - base::test::ScopedFeatureList feature_list_; - private: // InProcessBrowserTest: void SetUpOnMainThread() override { @@ -311,6 +287,7 @@ Profile::FromBrowserContext(context), std::move(fake_delegate)); } + base::test::ScopedFeatureList feature_list_; network::TestURLLoaderFactory test_url_loader_factory_; std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> identity_test_env_profile_adaptor_; @@ -408,100 +385,6 @@ EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); } -// Tests the complete interception flow including profile and browser creation. -IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, - ForcedEnterpriseInterceptionTest) { - base::HistogramTester histogram_tester; - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("alice@example.com"); - // Fill the account info, in particular for the hosted_domain field. - account_info.full_name = "fullname"; - account_info.given_name = "givenname"; - account_info.hosted_domain = "example.com"; - account_info.locale = "en"; - account_info.picture_url = "https://example.com"; - account_info.is_child_account = false; - DCHECK(account_info.IsValid()); - identity_test_env()->UpdateAccountInfoForAccount(account_info); - - // Enforce enterprise profile sepatation. - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - - // Instantly return from Gaia calls, to avoid timing out when injecting the - // account in the new profile. - network::TestURLLoaderFactory* loader_factory = test_url_loader_factory(); - loader_factory->SetInterceptor(base::BindLambdaForTesting( - [loader_factory](const network::ResourceRequest& request) { - std::string path = request.url.path(); - if (path == "/ListAccounts" || path == "/GetCheckConnectionInfo") { - loader_factory->AddResponse(request.url.spec(), std::string()); - return; - } - if (path == "/oauth/multilogin") { - loader_factory->AddResponse(request.url.spec(), - kMultiloginSuccessResponse); - return; - } - })); - - // Add a tab. - GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); - content::WebContents* web_contents = AddTab(intercepted_url); - int original_tab_count = browser()->tab_strip_model()->count(); - - // Do the signin interception. - EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); - FakeDiceWebSigninInterceptorDelegate* source_interceptor_delegate = - GetInterceptorDelegate(profile()); - source_interceptor_delegate->set_expected_enteprise_confirmation_result(true); - Profile* new_profile = - InterceptAndWaitProfileCreation(web_contents, account_info.account_id); - EXPECT_TRUE(new_profile->GetPrefs()->GetBoolean( - prefs::kUserAcceptedAccountManagement)); - ASSERT_TRUE(new_profile); - EXPECT_FALSE(source_interceptor_delegate->intercept_bubble_shown()); - signin::IdentityManager* new_identity_manager = - IdentityManagerFactory::GetForProfile(new_profile); - EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( - account_info.account_id)); - - IdentityTestEnvironmentProfileAdaptor adaptor(new_profile); - adaptor.identity_test_env()->SetAutomaticIssueOfAccessTokens(true); - - // Check the profile name. - ProfileAttributesStorage& storage = - g_browser_process->profile_manager()->GetProfileAttributesStorage(); - ProfileAttributesEntry* entry = - storage.GetProfileAttributesWithPath(new_profile->GetPath()); - ASSERT_TRUE(entry); - EXPECT_EQ("example.com", base::UTF16ToUTF8(entry->GetLocalProfileName())); - // Check the profile color. - EXPECT_TRUE(ThemeServiceFactory::GetForProfile(new_profile) - ->UsingAutogeneratedTheme()); - - // A browser has been created for the new profile and the tab was moved there. - Browser* added_browser = ui_test_utils::WaitForBrowserToOpen(); - ASSERT_TRUE(added_browser); - ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); - EXPECT_EQ(added_browser->profile(), new_profile); - EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); - EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), - intercepted_url); - - CheckHistograms( - histogram_tester, - SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); - // Interception bubble is destroyed in the source profile, and was not shown - // in the new profile. - FakeDiceWebSigninInterceptorDelegate* new_interceptor_delegate = - GetInterceptorDelegate(new_profile); - - // Profile customization UI was shown exactly once in the new profile. - EXPECT_EQ(new_interceptor_delegate->customized_browser(), added_browser); - EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); -} - // Tests the complete profile switch flow when the profile is not loaded. IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, SwitchAndLoad) { base::HistogramTester histogram_tester; @@ -773,180 +656,3 @@ SigninInterceptionHeuristicOutcome::kInterceptMultiUser, /*intercept_to_guest =*/true); } - -class DiceWebSigninInterceptorEnterpriseSwitchBrowserTest - : public DiceWebSigninInterceptorBrowserTest { - public: - DiceWebSigninInterceptorEnterpriseSwitchBrowserTest() { - enterprise_feature_list_.InitAndEnableFeature( - kAccountPoliciesLoadedWithoutSync); - } - - private: - base::test::ScopedFeatureList enterprise_feature_list_; -}; - -// Tests the complete profile switch flow when the profile is not loaded. -IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorEnterpriseSwitchBrowserTest, - EnterpriseSwitchAndLoad) { - base::HistogramTester histogram_tester; - // Enforce enterprise profile sepatation. - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("alice@example.com"); - // Fill the account info, in particular for the hosted_domain field. - account_info.full_name = "fullname"; - account_info.given_name = "givenname"; - account_info.hosted_domain = "example.com"; - account_info.locale = "en"; - account_info.picture_url = "https://example.com"; - account_info.is_child_account = false; - DCHECK(account_info.IsValid()); - identity_test_env()->UpdateAccountInfoForAccount(account_info); - - // Add a profile in the cache (simulate the profile on disk). - ProfileManager* profile_manager = g_browser_process->profile_manager(); - ProfileAttributesStorage* profile_storage = - &profile_manager->GetProfileAttributesStorage(); - const base::FilePath profile_path = - profile_manager->GenerateNextProfileDirectoryPath(); - ProfileAttributesInitParams params; - params.profile_path = profile_path; - params.profile_name = u"TestProfileName"; - params.gaia_id = account_info.gaia; - params.user_name = base::UTF8ToUTF16(account_info.email); - profile_storage->AddProfile(std::move(params)); - ProfileAttributesEntry* entry = - profile_storage->GetProfileAttributesWithPath(profile_path); - ASSERT_TRUE(entry); - ASSERT_EQ(entry->GetGAIAId(), account_info.gaia); - - // Add a tab. - GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); - content::WebContents* web_contents = AddTab(intercepted_url); - int original_tab_count = browser()->tab_strip_model()->count(); - - // Do the signin interception. - FakeDiceWebSigninInterceptorDelegate* source_interceptor_delegate = - GetInterceptorDelegate(profile()); - source_interceptor_delegate->set_expected_interception_type( - DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch); - Profile* new_profile = - InterceptAndWaitProfileCreation(web_contents, account_info.account_id); - ASSERT_TRUE(new_profile); - EXPECT_FALSE(source_interceptor_delegate->intercept_bubble_shown()); - signin::IdentityManager* new_identity_manager = - IdentityManagerFactory::GetForProfile(new_profile); - EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( - account_info.account_id)); - - // Check that the right profile was opened. - EXPECT_EQ(new_profile->GetPath(), profile_path); - - // Add the account to the cookies (simulates the account reconcilor). - EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); - signin::SetCookieAccounts(new_identity_manager, test_url_loader_factory(), - {{account_info.email, account_info.gaia}}); - - // A browser has been created for the new profile and the tab was moved there. - ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); - Browser* added_browser = BrowserList::GetInstance()->get(1); - ASSERT_TRUE(added_browser); - EXPECT_EQ(added_browser->profile(), new_profile); - EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); - EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), - intercepted_url); - - CheckHistograms(histogram_tester, - SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch); - - // Profile customization was not shown. - EXPECT_EQ(GetInterceptorDelegate(new_profile)->customized_browser(), nullptr); - EXPECT_EQ(source_interceptor_delegate->customized_browser(), nullptr); -} - -// Tests the complete profile switch flow when the profile is already loaded. -IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorEnterpriseSwitchBrowserTest, - EnterpriseSwitchAlreadyOpen) { - base::HistogramTester histogram_tester; - // Enforce enterprise profile sepatation. - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("alice@example.com"); - // Fill the account info, in particular for the hosted_domain field. - account_info.full_name = "fullname"; - account_info.given_name = "givenname"; - account_info.hosted_domain = "example.com"; - account_info.locale = "en"; - account_info.picture_url = "https://example.com"; - account_info.is_child_account = false; - DCHECK(account_info.IsValid()); - identity_test_env()->UpdateAccountInfoForAccount(account_info); - // Create another profile with a browser window. - ProfileManager* profile_manager = g_browser_process->profile_manager(); - const base::FilePath profile_path = - profile_manager->GenerateNextProfileDirectoryPath(); - base::RunLoop loop; - Profile* other_profile = nullptr; - ProfileManager::CreateCallback callback = base::BindLambdaForTesting( - [&other_profile, &loop](Profile* profile, Profile::CreateStatus status) { - DCHECK_EQ(status, Profile::CREATE_STATUS_INITIALIZED); - other_profile = profile; - loop.Quit(); - }); - profiles::SwitchToProfile(profile_path, /*always_create=*/true, - std::move(callback)); - loop.Run(); - ASSERT_TRUE(other_profile); - ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); - Browser* other_browser = BrowserList::GetInstance()->get(1); - ASSERT_TRUE(other_browser); - ASSERT_EQ(other_browser->profile(), other_profile); - // Add the account to the other profile. - signin::IdentityManager* other_identity_manager = - IdentityManagerFactory::GetForProfile(other_profile); - other_identity_manager->GetAccountsMutator()->AddOrUpdateAccount( - account_info.gaia, account_info.email, "dummy_refresh_token", - /*is_under_advanced_protection=*/false, - signin_metrics::SourceForRefreshTokenOperation::kUnknown); - other_identity_manager->GetPrimaryAccountMutator()->SetPrimaryAccount( - account_info.account_id, signin::ConsentLevel::kSync); - - // Add a tab. - GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); - content::WebContents* web_contents = AddTab(intercepted_url); - int original_tab_count = browser()->tab_strip_model()->count(); - int other_original_tab_count = other_browser->tab_strip_model()->count(); - - // Start the interception. - GetInterceptorDelegate(profile())->set_expected_interception_type( - DiceWebSigninInterceptor::SigninInterceptionType::kProfileSwitch); - DiceWebSigninInterceptor* interceptor = - DiceWebSigninInterceptorFactory::GetForProfile(profile()); - interceptor->MaybeInterceptWebSignin(web_contents, account_info.account_id, - /*is_new_account=*/true, - /*is_sync_signin=*/false); - - // Add the account to the cookies (simulates the account reconcilor). - signin::SetCookieAccounts(other_identity_manager, test_url_loader_factory(), - {{account_info.email, account_info.gaia}}); - - // The tab was moved to the new browser. - ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); - EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); - EXPECT_EQ(other_browser->tab_strip_model()->count(), - other_original_tab_count + 1); - EXPECT_EQ(other_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), - intercepted_url); - - CheckHistograms(histogram_tester, - SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch); - // Profile customization was not shown. - EXPECT_EQ(GetInterceptorDelegate(other_profile)->customized_browser(), - nullptr); - EXPECT_EQ(GetInterceptorDelegate(profile())->customized_browser(), nullptr); -}
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc index 08ee2a9..b499455 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -26,13 +26,11 @@ #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/prefs/pref_service.h" -#include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" namespace { @@ -46,12 +44,6 @@ const BubbleParameters& bubble_parameters, base::OnceCallback<void(SigninInterceptionResult)> callback), (override)); - MOCK_METHOD(void, - ShowEnterpriseProfileInterceptionDialog, - (const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser), - (override)); void ShowProfileCustomizationBubble(Browser* browser) override {} }; @@ -152,29 +144,6 @@ SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); } - // Calls MaybeInterceptWebSignin and verifies the heuristic outcome and the - // histograms. - // This function only works if the interception decision cannot be made - // synchronously (GetHeuristicOutcome() returns no value). - void TestAsynchronousInterception( - AccountInfo account_info, - bool is_new_account, - bool is_sync_signin, - SigninInterceptionHeuristicOutcome expected_outcome) { - ASSERT_EQ(interceptor()->GetHeuristicOutcome(is_new_account, is_sync_signin, - account_info.email, - /*entry=*/nullptr), - absl::nullopt); - base::HistogramTester histogram_tester; - interceptor()->MaybeInterceptWebSignin(web_contents(), - account_info.account_id, - is_new_account, is_sync_signin); - testing::Mock::VerifyAndClearExpectations(mock_delegate()); - histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", - expected_outcome, 1); - EXPECT_TRUE(interceptor()->is_interception_in_progress()); - } - private: // testing::Test: void SetUp() override { @@ -319,161 +288,6 @@ EXPECT_TRUE(interceptor()->ShouldShowEnterpriseBubble(account_info)); } -TEST_F(DiceWebSigninInterceptorTest, ShouldEnforceEnterpriseProfileSeparation) { - profile()->GetPrefs()->SetBoolean( - prefs::kManagedAccountsSigninRestrictionScopeMachine, true); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - - // Setup 3 accounts in the profile: - // - primary account - // - other enterprise account that is not primary (should be ignored) - // - intercepted account. - AccountInfo primary_account_info = - identity_test_env()->MakeUnconsentedPrimaryAccountAvailable( - "alice@gmail.com"); - - AccountInfo other_account_info = - identity_test_env()->MakeAccountAvailable("dummy@example.com"); - MakeValidAccountInfo(&other_account_info); - other_account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(other_account_info); - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("bob@example.com"); - MakeValidAccountInfo(&account_info); - identity_test_env()->UpdateAccountInfoForAccount(account_info); - ASSERT_EQ(identity_test_env()->identity_manager()->GetPrimaryAccountId( - signin::ConsentLevel::kSignin), - primary_account_info.account_id); - // Consumer account not intercepted. - EXPECT_FALSE( - interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); - account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(account_info); - // Managed account intercepted. - EXPECT_TRUE( - interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); -} - -TEST_F(DiceWebSigninInterceptorTest, - ShouldEnforceEnterpriseProfileSeparationWithoutUPA) { - profile()->GetPrefs()->SetBoolean( - prefs::kManagedAccountsSigninRestrictionScopeMachine, true); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - AccountInfo account_info_1 = - identity_test_env()->MakeAccountAvailable("bob@example.com"); - MakeValidAccountInfo(&account_info_1); - account_info_1.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(account_info_1); - - // Primary account is not set. - ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( - signin::ConsentLevel::kSignin)); - EXPECT_TRUE( - interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info_1)); -} - -TEST_F(DiceWebSigninInterceptorTest, - ShouldEnforceEnterpriseProfileSeparationReauth) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(kAccountPoliciesLoadedWithoutSync); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - AccountInfo primary_account_info = - identity_test_env()->MakeUnconsentedPrimaryAccountAvailable( - "alice@example.com"); - MakeValidAccountInfo(&primary_account_info); - primary_account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); - - // Primary account is set. - ASSERT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount( - signin::ConsentLevel::kSignin)); - EXPECT_TRUE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( - primary_account_info)); - - profile()->GetPrefs()->SetBoolean(prefs::kUserAcceptedAccountManagement, - true); - EXPECT_FALSE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( - primary_account_info)); -} - -TEST_F(DiceWebSigninInterceptorTest, EnforceManagedAccountAsPrimaryReauth) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(kAccountPoliciesLoadedWithoutSync); - profile()->GetPrefs()->SetBoolean( - prefs::kManagedAccountsSigninRestrictionScopeMachine, true); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account"); - - // Reauth intercepted if enterprise confirmation not shown yet for forced - // managed separation. - AccountInfo account_info = - identity_test_env()->MakeUnconsentedPrimaryAccountAvailable( - "alice@example.com"); - MakeValidAccountInfo(&account_info); - account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(account_info); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account"); - EXPECT_CALL(*mock_delegate(), ShowEnterpriseProfileInterceptionDialog( - testing::_, testing::_, testing::_)) - .WillOnce(testing::Invoke( - [](const std::string& email, base::OnceCallback<void(bool)> callback, - Browser* browser) { std::move(callback).Run(true); })); - TestAsynchronousInterception( - account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, - SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); -} - -TEST_F(DiceWebSigninInterceptorTest, EnforceManagedAccountAsPrimaryManaged) { - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("alice@example.com"); - MakeValidAccountInfo(&account_info); - account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(account_info); - - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - - EXPECT_CALL(*mock_delegate(), ShowEnterpriseProfileInterceptionDialog( - testing::_, testing::_, testing::_)) - .WillOnce(testing::Invoke( - [](const std::string& email, base::OnceCallback<void(bool)> callback, - Browser* browser) { std::move(callback).Run(true); })); - TestAsynchronousInterception( - account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, - SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); -} - -TEST_F(DiceWebSigninInterceptorTest, - EnforceManagedAccountAsPrimaryProfileSwitch) { - AccountInfo account_info = - identity_test_env()->MakeAccountAvailable("alice@example.com"); - MakeValidAccountInfo(&account_info); - account_info.hosted_domain = "example.com"; - identity_test_env()->UpdateAccountInfoForAccount(account_info); - - profile()->GetPrefs()->SetBoolean( - prefs::kManagedAccountsSigninRestrictionScopeMachine, true); - profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, - "primary_account_strict"); - - // Setup for profile switch interception. - Profile* profile_2 = CreateTestingProfile("Profile 2"); - ProfileAttributesEntry* entry = - profile_attributes_storage()->GetProfileAttributesWithPath( - profile_2->GetPath()); - ASSERT_NE(entry, nullptr); - entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(account_info.email), - /*is_consented_primary_account=*/false); - TestAsynchronousInterception(account_info, /*is_new_account=*/true, - /*is_sync_signin=*/false, - SigninInterceptionHeuristicOutcome:: - kInterceptEnterpriseForcedProfileSwitch); -} - TEST_F(DiceWebSigninInterceptorTest, ShouldShowEnterpriseBubbleWithoutUPA) { AccountInfo account_info_1 = identity_test_env()->MakeAccountAvailable("bob@example.com");
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc index 47fbdd15..d362eba 100644 --- a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc +++ b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
@@ -50,14 +50,6 @@ std::move(callback).Run(SigninInterceptionResult::kDeclined); return nullptr; } - - void ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) override { - std::move(callback).Run(false); - } - void ShowProfileCustomizationBubble(Browser* browser) override {} };
diff --git a/chrome/browser/speech/fake_speech_recognition_service.cc b/chrome/browser/speech/fake_speech_recognition_service.cc index ca08c4f3..2bc1564 100644 --- a/chrome/browser/speech/fake_speech_recognition_service.cc +++ b/chrome/browser/speech/fake_speech_recognition_service.cc
@@ -69,14 +69,13 @@ } void FakeSpeechRecognitionService::SendSpeechRecognitionResult( - media::mojom::SpeechRecognitionResultPtr result) { + const media::SpeechRecognitionResult& result) { ASSERT_TRUE(recognizer_client_remote_.is_bound()); EXPECT_TRUE(capturing_audio_ || has_received_audio_); recognizer_client_remote_->OnSpeechRecognitionRecognitionEvent( - std::move(result), - base::BindOnce(&FakeSpeechRecognitionService:: - OnSpeechRecognitionRecognitionEventCallback, - base::Unretained(this))); + result, base::BindOnce(&FakeSpeechRecognitionService:: + OnSpeechRecognitionRecognitionEventCallback, + base::Unretained(this))); } void FakeSpeechRecognitionService::OnSpeechRecognitionRecognitionEventCallback(
diff --git a/chrome/browser/speech/fake_speech_recognition_service.h b/chrome/browser/speech/fake_speech_recognition_service.h index f8d4855..75ac0ec 100644 --- a/chrome/browser/speech/fake_speech_recognition_service.h +++ b/chrome/browser/speech/fake_speech_recognition_service.h
@@ -61,7 +61,7 @@ // Methods for testing plumbing to SpeechRecognitionRecognizerClient. void SendSpeechRecognitionResult( - media::mojom::SpeechRecognitionResultPtr result); + const media::SpeechRecognitionResult& result); void SendSpeechRecognitionError(); void WaitForRecognitionStarted();
diff --git a/chrome/browser/speech/network_speech_recognizer.cc b/chrome/browser/speech/network_speech_recognizer.cc index fdb1cc5..238e7c4 100644 --- a/chrome/browser/speech/network_speech_recognizer.cc +++ b/chrome/browser/speech/network_speech_recognizer.cc
@@ -225,7 +225,7 @@ FROM_HERE, base::BindOnce(&SpeechRecognizerDelegate::OnSpeechResult, delegate_, result_str, final_count == results.size(), - absl::nullopt /* word offsets */)); + /* full_result = */ absl::nullopt)); last_result_str_ = result_str; }
diff --git a/chrome/browser/speech/network_speech_recognizer_browsertest.cc b/chrome/browser/speech/network_speech_recognizer_browsertest.cc index 4ddb855..f4f457b 100644 --- a/chrome/browser/speech/network_speech_recognizer_browsertest.cc +++ b/chrome/browser/speech/network_speech_recognizer_browsertest.cc
@@ -24,6 +24,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/fake_speech_recognition_manager.h" #include "content/public/test/test_utils.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -43,8 +44,7 @@ OnSpeechResult, void(const std::u16string& text, bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& - timing)); + const absl::optional<media::SpeechRecognitionResult>& timing)); MOCK_METHOD1(OnSpeechSoundLevelChanged, void(int16_t)); MOCK_METHOD1(OnSpeechRecognitionStateChanged, void(SpeechRecognizerStatus));
diff --git a/chrome/browser/speech/on_device_speech_recognizer.cc b/chrome/browser/speech/on_device_speech_recognizer.cc index afd8cf1..f42a521 100644 --- a/chrome/browser/speech/on_device_speech_recognizer.cc +++ b/chrome/browser/speech/on_device_speech_recognizer.cc
@@ -131,18 +131,18 @@ } void OnDeviceSpeechRecognizer::OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResultPtr result, + const media::SpeechRecognitionResult& result, OnSpeechRecognitionRecognitionEventCallback reply) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // Returning true ensures the speech recognition continues. std::move(reply).Run(true); - if (!result->transcription.size()) + if (!result.transcription.size()) return; UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_IN_SPEECH); - delegate()->OnSpeechResult(base::UTF8ToUTF16(result->transcription), - result->is_final, absl::nullopt); + delegate()->OnSpeechResult(base::UTF8ToUTF16(result.transcription), + result.is_final, result); } void OnDeviceSpeechRecognizer::OnSpeechRecognitionError() {
diff --git a/chrome/browser/speech/on_device_speech_recognizer.h b/chrome/browser/speech/on_device_speech_recognizer.h index 0ae7e29..8b871f1 100644 --- a/chrome/browser/speech/on_device_speech_recognizer.h +++ b/chrome/browser/speech/on_device_speech_recognizer.h
@@ -56,7 +56,7 @@ // media::mojom::SpeechRecognitionRecognizerClient: void OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResultPtr result, + const media::SpeechRecognitionResult& result, OnSpeechRecognitionRecognitionEventCallback reply) override; void OnSpeechRecognitionError() override; void OnLanguageIdentificationEvent(
diff --git a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc index 55d88b8..3f5de01 100644 --- a/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc +++ b/chrome/browser/speech/on_device_speech_recognizer_browsertest.cc
@@ -18,6 +18,7 @@ #include "content/public/test/browser_test.h" #include "media/audio/audio_system.h" #include "media/base/audio_parameters.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,8 +42,7 @@ OnSpeechResult, void(const std::u16string& text, bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& - timing)); + const absl::optional<media::SpeechRecognitionResult>& timing)); MOCK_METHOD1(OnSpeechSoundLevelChanged, void(int16_t)); MOCK_METHOD1(OnSpeechRecognitionStateChanged, void(SpeechRecognizerStatus)); @@ -206,8 +206,7 @@ .Times(1) .RetiresOnSaturation(); fake_service_->SendSpeechRecognitionResult( - media::mojom::SpeechRecognitionResult::New("All mammals have hair", - false)); + media::SpeechRecognitionResult("All mammals have hair", false)); base::RunLoop().RunUntilIdle(); EXPECT_CALL(*mock_speech_delegate_, @@ -216,9 +215,8 @@ true, testing::_)) .Times(1) .RetiresOnSaturation(); - fake_service_->SendSpeechRecognitionResult( - media::mojom::SpeechRecognitionResult::New( - "All mammals drink milk from their mothers", true)); + fake_service_->SendSpeechRecognitionResult(media::SpeechRecognitionResult( + "All mammals drink milk from their mothers", true)); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/browser/speech/speech_recognizer_delegate.cc b/chrome/browser/speech/speech_recognizer_delegate.cc deleted file mode 100644 index aa8101a..0000000 --- a/chrome/browser/speech/speech_recognizer_delegate.cc +++ /dev/null
@@ -1,9 +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 "chrome/browser/speech/speech_recognizer_delegate.h" - -SpeechRecognizerDelegate::TranscriptTiming::TranscriptTiming() = default; - -SpeechRecognizerDelegate::TranscriptTiming::~TranscriptTiming() = default;
diff --git a/chrome/browser/speech/speech_recognizer_delegate.h b/chrome/browser/speech/speech_recognizer_delegate.h index 84f3db9..f8fb236 100644 --- a/chrome/browser/speech/speech_recognizer_delegate.h +++ b/chrome/browser/speech/speech_recognizer_delegate.h
@@ -9,6 +9,7 @@ #include <string> #include "base/time/time.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" // Requires cleanup. See crbug.com/800374. @@ -28,38 +29,15 @@ // which this delegate was constructed. class SpeechRecognizerDelegate { public: - // The timing information for the recognized speech text. - struct TranscriptTiming { - TranscriptTiming(); - TranscriptTiming(const TranscriptTiming&) = delete; - TranscriptTiming& operator=(const TranscriptTiming&) = delete; - ~TranscriptTiming(); - - // Describes the time that elapsed between the start of speech recognition - // session and the first audio input that corresponds to the transcription - // result. - base::TimeDelta audio_start_time; - - // Describes the time that elapsed between the start of speech recognition - // and the last audio input that corresponds to the transcription result. - base::TimeDelta audio_end_time; - - // Describes the time that elapsed between the start of speech recognition - // and the audio input corresponding to each word in the transcription - // result. The vector will have the same number of TimeDeltas as the - // transcription result. - std::vector<base::TimeDelta> word_offsets; - }; - // Receive a speech recognition result. |is_final| indicated whether the // result is an intermediate or final result. If |is_final| is true, then the // recognizer stops and no more results will be returned. - // May include word timing information in |timing| if the speech recognizer is - // an on device speech recognizer. + // May include word timing information in |full_result| if the speech + // recognizer is an on device speech recognizer. virtual void OnSpeechResult( const std::u16string& text, bool is_final, - const absl::optional<TranscriptTiming>& timing) = 0; + const absl::optional<media::SpeechRecognitionResult>& full_result) = 0; // Invoked regularly to indicate the average sound volume. virtual void OnSpeechSoundLevelChanged(int16_t level) = 0;
diff --git a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc index ed215c18..bb36f68 100644 --- a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc +++ b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/containers/contains.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/history_test_utils.h" @@ -533,32 +534,63 @@ 0); } +// Flaky on Mac. See https://crbug.com/1216086 +#if defined(OS_MAC) +#define MAYBE_SearchQuery_ShouldNotUpgrade DISABLED_SearchQuery_ShouldNotUpgrade +#else +#define MAYBE_SearchQuery_ShouldNotUpgrade SearchQuery_ShouldNotUpgrade +#endif // Test the case when the user types a search keyword. The keyword may or may // not be a non-unique hostname. The navigation should always result in a // search and we should never upgrade it to https. IN_PROC_BROWSER_TEST_P(TypedNavigationUpgradeThrottleBrowserTest, - SearchQuery_ShouldNotUpgrade) { + MAYBE_SearchQuery_ShouldNotUpgrade) { TypeUrlAndExpectNoUpgrade("testpage", /*expect_search_query=*/true); } +// Flaky on Mac. See https://crbug.com/1216086 +#if defined(OS_MAC) +#define MAYBE_SearchQuery_TwoWords_ShouldNotUpgrade \ + DISABLED_SearchQuery_TwoWords_ShouldNotUpgrade +#else +#define MAYBE_SearchQuery_TwoWords_ShouldNotUpgrade \ + SearchQuery_TwoWords_ShouldNotUpgrade +#endif // Same as SearchQuery_ShouldNotUpgrade but with two words. This is a definite // search query, and can never be a hostname. IN_PROC_BROWSER_TEST_P(TypedNavigationUpgradeThrottleBrowserTest, - SearchQuery_TwoWords_ShouldNotUpgrade) { + MAYBE_SearchQuery_TwoWords_ShouldNotUpgrade) { TypeUrlAndExpectNoUpgrade("test page", /*expect_search_query=*/true); } +// Flaky on Mac. See https://crbug.com/1216086 +#if defined(OS_MAC) +#define MAYBE_NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade \ + DISABLED_NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade +#else +#define MAYBE_NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade \ + NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade +#endif // Test the case when the user types a non-unique hostname. We shouldn't upgrade // it to https. -IN_PROC_BROWSER_TEST_P(TypedNavigationUpgradeThrottleBrowserTest, - NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade) { +IN_PROC_BROWSER_TEST_P( + TypedNavigationUpgradeThrottleBrowserTest, + MAYBE_NonUniqueHostnameTypedWithoutScheme_ShouldNotUpgrade) { TypeUrlAndExpectNoUpgrade(kNonUniqueHostname2, /*expect_search_query=*/false); } +// Flaky on Mac. See https://crbug.com/1216086 +#if defined(OS_MAC) +#define MAYBE_IPAddressTypedWithoutScheme_ShouldNotUpgrade \ + DISABLED_IPAddressTypedWithoutScheme_ShouldNotUpgrade +#else +#define MAYBE_IPAddressTypedWithoutScheme_ShouldNotUpgrade \ + IPAddressTypedWithoutScheme_ShouldNotUpgrade +#endif // Test the case when the user types an IP address. We shouldn't upgrade it to // https. IN_PROC_BROWSER_TEST_P(TypedNavigationUpgradeThrottleBrowserTest, - IPAddressTypedWithoutScheme_ShouldNotUpgrade) { + MAYBE_IPAddressTypedWithoutScheme_ShouldNotUpgrade) { TypeUrlAndExpectNoUpgrade("127.0.0.1", /*expect_search_query=*/false); }
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc index a584fba..cf29bf72 100644 --- a/chrome/browser/supervised_user/supervised_user_service.cc +++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -124,6 +124,17 @@ return denylist_dir.AppendASCII(kDenylistFilename); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +bool AreWebFilterPrefsDefault(PrefService* pref_service) { + return pref_service + ->FindPreference(prefs::kDefaultSupervisedUserFilteringBehavior) + ->IsDefaultValue() || + pref_service->FindPreference(prefs::kSupervisedUserSafeSites) + ->IsDefaultValue(); +} + +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + } // namespace SupervisedUserService::~SupervisedUserService() { @@ -205,8 +216,8 @@ } std::string SupervisedUserService::GetCustodianEmailAddress() const { - std::string email = profile_->GetPrefs()->GetString( - prefs::kSupervisedUserCustodianEmail); + std::string email = + profile_->GetPrefs()->GetString(prefs::kSupervisedUserCustodianEmail); #if BUILDFLAG(IS_CHROMEOS_ASH) // |GetActiveUser()| can return null in unit tests. if (email.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) { @@ -227,8 +238,8 @@ } std::string SupervisedUserService::GetCustodianName() const { - std::string name = profile_->GetPrefs()->GetString( - prefs::kSupervisedUserCustodianName); + std::string name = + profile_->GetPrefs()->GetString(prefs::kSupervisedUserCustodianName); #if BUILDFLAG(IS_CHROMEOS_ASH) // |GetActiveUser()| can return null in unit tests. if (name.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) { @@ -401,11 +412,15 @@ } #endif // BUILDFLAG(ENABLE_EXTENSIONS) -bool SupervisedUserService::IsFilteringBehaviorPrefDefault() const { - return profile_->GetPrefs() - ->FindPreference(prefs::kDefaultSupervisedUserFilteringBehavior) - ->IsDefaultValue(); +#if BUILDFLAG(IS_CHROMEOS_ASH) +void SupervisedUserService::ReportNonDefaultWebFilterValue() const { + if (AreWebFilterPrefsDefault(profile_->GetPrefs())) + return; + + url_filter_.ReportManagedSiteListMetrics(); + url_filter_.ReportWebFilterTypeMetrics(); } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) void SupervisedUserService::SetActive(bool active) { if (active_ == active) @@ -471,6 +486,11 @@ UpdateManualHosts(); UpdateManualURLs(); +#if BUILDFLAG(IS_CHROMEOS_ASH) + GetURLFilter()->SetFilterInitialized(true); + current_web_filter_type_ = url_filter_.GetWebFilterType(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + #if BUILDFLAG(ENABLE_EXTENSIONS) RefreshApprovedExtensionsFromPrefs(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) @@ -576,6 +596,16 @@ for (SupervisedUserServiceObserver& observer : observer_list_) observer.OnURLFilterChanged(); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + SupervisedUserURLFilter::WebFilterType filter_type = + url_filter_.GetWebFilterType(); + if (!AreWebFilterPrefsDefault(profile_->GetPrefs()) && + current_web_filter_type_ != filter_type) { + url_filter_.ReportWebFilterTypeMetrics(); + current_web_filter_type_ = filter_type; + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } void SupervisedUserService::OnSafeSitesSettingChanged() { @@ -593,6 +623,16 @@ } UpdateAsyncUrlChecker(); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + SupervisedUserURLFilter::WebFilterType filter_type = + url_filter_.GetWebFilterType(); + if (!AreWebFilterPrefsDefault(profile_->GetPrefs()) && + current_web_filter_type_ != filter_type) { + url_filter_.ReportWebFilterTypeMetrics(); + current_web_filter_type_ = filter_type; + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } void SupervisedUserService::UpdateAsyncUrlChecker() { @@ -726,6 +766,11 @@ for (SupervisedUserServiceObserver& observer : observer_list_) observer.OnURLFilterChanged(); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (!AreWebFilterPrefsDefault(profile_->GetPrefs())) + url_filter_.ReportManagedSiteListMetrics(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } void SupervisedUserService::UpdateManualURLs() { @@ -740,6 +785,11 @@ for (SupervisedUserServiceObserver& observer : observer_list_) observer.OnURLFilterChanged(); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (!AreWebFilterPrefsDefault(profile_->GetPrefs())) + url_filter_.ReportManagedSiteListMetrics(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } void SupervisedUserService::Shutdown() {
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h index d106990..4faab14 100644 --- a/chrome/browser/supervised_user/supervised_user_service.h +++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -18,6 +18,7 @@ #include "base/observer_list.h" #include "base/scoped_observation.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/net/file_downloader.h" #include "chrome/browser/supervised_user/supervised_user_denylist.h" #include "chrome/browser/supervised_user/supervised_user_url_filter.h" @@ -220,9 +221,11 @@ void RecordExtensionEnablementUmaMetrics(bool enabled) const; #endif // BUILDFLAG(ENABLE_EXTENSIONS) - // Returns true if prefs::kDefaultSupervisedUserFilteringBehavior is set to - // default value. - bool IsFilteringBehaviorPrefDefault() const; +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Reports FamilyUser.WebFilterType and FamilyUser.ManagedSiteList metrics. + // Igores reporting when AreWebFilterPrefsDefault() is true. + void ReportNonDefaultWebFilterValue() const; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) private: friend class SupervisedUserServiceExtensionTestBase; @@ -409,6 +412,16 @@ bool signout_required_after_supervision_enabled_ = false; #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) + // When there is change between WebFilterType::kTryToBlockMatureSites and + // WebFilterType::kCertainSites, both + // prefs::kDefaultSupervisedUserFilteringBehavior and + // prefs::kSupervisedUserSafeSites change. Uses this member to avoid duplicate + // reports. Initialized in the SetActive(). + SupervisedUserURLFilter::WebFilterType current_web_filter_type_ = + SupervisedUserURLFilter::WebFilterType::kMaxValue; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + base::WeakPtrFactory<SupervisedUserService> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(SupervisedUserService);
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc index cc1a22e2..0c60f5b 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.cc +++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -48,6 +48,10 @@ #include "extensions/common/extension_urls.h" #endif +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "base/metrics/histogram_functions.h" +#endif + using content::BrowserThread; using net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES; using net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES; @@ -123,6 +127,18 @@ // accounts.google.com used for login: const char kAccountsGoogleUrl[] = "https://accounts.google.com"; +#if BUILDFLAG(IS_CHROMEOS_ASH) +// UMA histogram FamilyUser.WebFilterType +// Reports WebFilterType which indicates web filter behaviour are used for +// current Family Link user on Chrome OS. +constexpr char kWebFilterTypeHistogramName[] = "FamilyUser.WebFilterType"; + +// UMA histogram FamilyUser.ManualSiteListType +// Reports ManualSiteListType which indicates approved list and blocked list +// usage for current Family Link user on Chrome OS. +constexpr char kManagedSiteListHistogramName[] = "FamilyUser.ManagedSiteList"; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // This class encapsulates all the state that is required during construction of // a new SupervisedUserURLFilter::Contents. class FilterBuilder { @@ -239,6 +255,19 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +// static +const char* SupervisedUserURLFilter::GetWebFilterTypeHistogramNameForTest() { + return kWebFilterTypeHistogramName; +} + +// static +const char* SupervisedUserURLFilter::GetManagedSiteListHistogramNameForTest() { + return kManagedSiteListHistogramName; +} + +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // static bool SupervisedUserURLFilter::ShouldSkipParentManualAllowlistFiltering( content::WebContents* contents) { @@ -681,12 +710,25 @@ : WebFilterType::kAllowAllSites; } -SupervisedUserURLFilter::ManagedSiteList -SupervisedUserURLFilter ::GetManagedSiteList() const { +void SupervisedUserURLFilter::ReportWebFilterTypeMetrics() const { + if (!is_filter_initialized_) + return; + + base::UmaHistogramEnumeration(kWebFilterTypeHistogramName, + GetWebFilterType()); +} + +void SupervisedUserURLFilter::ReportManagedSiteListMetrics() const { + if (!is_filter_initialized_) + return; + if (url_map_.empty() && host_map_.empty()) { - return ManagedSiteList::kEmpty; + base::UmaHistogramEnumeration(kManagedSiteListHistogramName, + ManagedSiteList::kEmpty); + return; } + ManagedSiteList managed_site_list = ManagedSiteList::kMaxValue; bool approved_list = false; bool blocked_list = false; for (const auto& it : url_map_) { @@ -710,12 +752,19 @@ } if (approved_list && blocked_list) { - return ManagedSiteList::kBoth; + managed_site_list = ManagedSiteList::kBoth; } else if (approved_list) { - return ManagedSiteList::kApprovedListOnly; + managed_site_list = ManagedSiteList::kApprovedListOnly; } else { - return ManagedSiteList::kBlockedListOnly; + managed_site_list = ManagedSiteList::kBlockedListOnly; } + + base::UmaHistogramEnumeration(kManagedSiteListHistogramName, + managed_site_list); +} + +void SupervisedUserURLFilter::SetFilterInitialized(bool is_filter_initialized) { + is_filter_initialized_ = is_filter_initialized; } #endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.h b/chrome/browser/supervised_user/supervised_user_url_filter.h index 0cbbf5c8..eb7bdf8 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.h +++ b/chrome/browser/supervised_user/supervised_user_url_filter.h
@@ -128,6 +128,11 @@ SupervisedUserURLFilter(); ~SupervisedUserURLFilter(); +#if BUILDFLAG(IS_CHROMEOS_ASH) + static const char* GetWebFilterTypeHistogramNameForTest(); + static const char* GetManagedSiteListHistogramNameForTest(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Returns true if the parental allowlist/blocklist should be skipped in // |contents|. SafeSearch filtering is still applied to |contents|. static bool ShouldSkipParentManualAllowlistFiltering( @@ -242,10 +247,18 @@ const scoped_refptr<base::TaskRunner>& task_runner); #if BUILDFLAG(IS_CHROMEOS_ASH) - // // Returns WebFilterType for current web filter setting. WebFilterType GetWebFilterType() const; - // Returns ManagedSiteList for current web filter setting. - ManagedSiteList GetManagedSiteList() const; + + // Reports FamilyUser.WebFilterType metrics when `is_filter_initialized_` is + // true. + void ReportWebFilterTypeMetrics() const; + + // Reports FamilyUser.ManagedSiteList metrics when `is_filter_initialized_` is + // true. + void ReportManagedSiteListMetrics() const; + + // Set value for `is_filter_initialized_`. + void SetFilterInitialized(bool is_filter_initialized); #endif // BUILDFLAG(IS_CHROMEOS_ASH) private: @@ -289,6 +302,10 @@ SEQUENCE_CHECKER(sequence_checker_); +#if BUILDFLAG(IS_CHROMEOS_ASH) + bool is_filter_initialized_ = false; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + base::WeakPtrFactory<SupervisedUserURLFilter> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(SupervisedUserURLFilter);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index fe11d991..71c55fc4 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -4203,6 +4203,8 @@ "views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h", "views/send_tab_to_self/send_tab_to_self_icon_view.cc", "views/send_tab_to_self/send_tab_to_self_icon_view.h", + "views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.cc", + "views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h", "views/send_tab_to_self/send_tab_to_self_toolbar_button_view.cc", "views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h", "views/session_crashed_bubble_view.cc", @@ -4546,6 +4548,15 @@ ] } + if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { + sources += [ + "views/web_apps/web_app_url_handler_hover_button.cc", + "views/web_apps/web_app_url_handler_hover_button.h", + "views/web_apps/web_app_url_handler_intent_picker_dialog_view.cc", + "views/web_apps/web_app_url_handler_intent_picker_dialog_view.h", + ] + } + if (use_aura) { # These files can do Gtk+-based theming for builds with gtk enabled. if (is_linux || is_chromeos_lacros) {
diff --git a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java index bd9a9ac6b..20735887 100644 --- a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java +++ b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutStateProvider.java
@@ -60,6 +60,13 @@ boolean isLayoutVisible(@LayoutType int layoutType); /** + * Get the type of the layout that is currently active. + * @return The {@link LayoutType} of the active layout. + */ + @LayoutType + int getActiveLayoutType(); + + /** * @param listener Registers {@code listener} for all layout status changes. */ void addObserver(LayoutStateObserver listener);
diff --git a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java index 212219b8..fe26a24f 100644 --- a/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java +++ b/chrome/browser/ui/android/layouts/java/src/org/chromium/chrome/browser/layouts/LayoutType.java
@@ -13,10 +13,11 @@ * The type info of the Layout. These types are bit flags, so they can be or-ed together to test for * multiple. */ -@IntDef({LayoutType.BROWSING, LayoutType.TAB_SWITCHER, LayoutType.TOOLBAR_SWIPE, +@IntDef({LayoutType.NONE, LayoutType.BROWSING, LayoutType.TAB_SWITCHER, LayoutType.TOOLBAR_SWIPE, LayoutType.SIMPLE_ANIMATION}) @Retention(RetentionPolicy.SOURCE) public @interface LayoutType { + int NONE = 0; int BROWSING = 1; int TAB_SWITCHER = 2; int TOOLBAR_SWIPE = 4;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonController.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonController.java index b1de46c..721eb21 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonController.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonController.java
@@ -203,7 +203,7 @@ } private boolean shouldShowVoiceButton(Tab tab) { - if (!FeatureList.isInitialized() || !isFeatureEnabled() || tab == null || tab.isIncognito() + if (!isToolbarMicEnabled() || tab == null || tab.isIncognito() || !mVoiceSearchDelegate.isVoiceSearchEnabled()) { return false; } @@ -220,7 +220,9 @@ return UrlUtilities.isHttpOrHttps(tab.getUrl()); } - private static boolean isFeatureEnabled() { + /** Returns whether the feature flags allow showing the mic icon in the toolbar. */ + public static boolean isToolbarMicEnabled() { + if (!FeatureList.isInitialized()) return false; if (AdaptiveToolbarFeatures.isEnabled()) { return AdaptiveToolbarFeatures.getSingleVariantMode() == AdaptiveToolbarButtonVariant.VOICE;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java index cc7a0da..3094b84 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java
@@ -84,8 +84,7 @@ doReturn(mUrl).when(mTab).getUrl(); doReturn(mContext).when(mTab).getContext(); - - CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, false); + AdaptiveToolbarFeatures.clearParsedParamsForTesting(); // clang-format off mVoiceToolbarButtonController = new VoiceToolbarButtonController(mContext, mDrawable, () -> mTab, mActivityLifecycleDispatcher, mModalDialogManager, @@ -97,7 +96,9 @@ @DisableFeatures({ChromeFeatureList.TOOLBAR_MIC_IPH_ANDROID}) @Test public void onConfigurationChanged_screenWidthChanged() { + CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, false); AdaptiveToolbarFeatures.MODE_PARAM.setForTesting(AdaptiveToolbarFeatures.ALWAYS_NONE); + assertTrue(mVoiceToolbarButtonController.get(mTab).canShow()); // Screen width shrinks below the threshold (e.g. screen rotated). @@ -120,6 +121,7 @@ @Test public void testIPHCommandHelper() { + CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, false); AdaptiveToolbarFeatures.MODE_PARAM.setForTesting(AdaptiveToolbarFeatures.ALWAYS_NONE); assertNull(mVoiceToolbarButtonController.get(/*tab*/ null) .getButtonSpec() @@ -128,9 +130,34 @@ // Verify that IPHCommandBuilder is set just once; IPHCommandBuilder builder = mVoiceToolbarButtonController.get(mTab).getButtonSpec().getIPHCommandBuilder(); + assertNotNull( mVoiceToolbarButtonController.get(mTab).getButtonSpec().getIPHCommandBuilder()); assertEquals(builder, mVoiceToolbarButtonController.get(mTab).getButtonSpec().getIPHCommandBuilder()); } + + @Test + public void isToolbarMicEnabled_adaptiveButtons_nonVoice() { + CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, true); + AdaptiveToolbarFeatures.MODE_PARAM.setForTesting(AdaptiveToolbarFeatures.ALWAYS_SHARE); + + assertFalse(VoiceToolbarButtonController.isToolbarMicEnabled()); + } + + @Test + public void isToolbarMicEnabled_adaptiveButtons_voice() { + CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, true); + AdaptiveToolbarFeatures.MODE_PARAM.setForTesting(AdaptiveToolbarFeatures.ALWAYS_VOICE); + + assertTrue(VoiceToolbarButtonController.isToolbarMicEnabled()); + } + + @EnableFeatures({ChromeFeatureList.VOICE_BUTTON_IN_TOP_TOOLBAR}) + @Test + public void isToolbarMicEnabled_toolbarMic() { + CachedFeatureFlags.setForTesting(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, false); + + assertTrue(VoiceToolbarButtonController.isToolbarMicEnabled()); + } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java index 2d199ee..f4ec1fe 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarOverlayMediator.java
@@ -85,6 +85,9 @@ mModel = model; mIsVisibilityManuallyControlled = manualVisibilityControl; + mIsOnValidLayout = (mLayoutStateProvider.getActiveLayoutType() & layoutsToShowOn) > 0; + updateVisibility(); + mSceneChangeObserver = new LayoutStateObserver() { @Override public void onStartedShowing(@LayoutType int layout, boolean showToolbar) {
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc index fc08166..e8d6403 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.cc +++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -73,18 +73,9 @@ void ProjectorClientImpl::OnSpeechResult( const std::u16string& text, bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& timing) { - DCHECK(timing.has_value() || ShouldUseWebSpeechFallback()); - - if (timing.has_value()) { - ash::ProjectorController::Get()->OnTranscription( - text, timing->audio_start_time, timing->audio_end_time, - timing->word_offsets, is_final); - } else { - // This is only used for development. - ash::ProjectorController::Get()->OnTranscription( - text, absl::nullopt, absl::nullopt, absl::nullopt, is_final); - } + const absl::optional<media::SpeechRecognitionResult>& full_result) { + DCHECK(full_result.has_value()); + ash::ProjectorController::Get()->OnTranscription(full_result.value()); } void ProjectorClientImpl::OnSpeechRecognitionStateChanged(
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.h b/chrome/browser/ui/ash/projector/projector_client_impl.h index 0267575..26b26987 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.h +++ b/chrome/browser/ui/ash/projector/projector_client_impl.h
@@ -39,8 +39,7 @@ void OnSpeechResult( const std::u16string& text, bool is_final, - const absl::optional<SpeechRecognizerDelegate::TranscriptTiming>& timing) - override; + const absl::optional<media::SpeechRecognitionResult>& timing) override; // This class is not utilizing the information about sound level. void OnSpeechSoundLevelChanged(int16_t level) override {} void OnSpeechRecognitionStateChanged(
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc index fb66c63..0e5e189 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -21,6 +21,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/launch_utils.h" +#include "chrome/browser/ash/backdrop_wallpaper_handlers/backdrop_wallpaper.pb.h" #include "chrome/browser/ash/customization/customization_wallpaper_util.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/browser_process.h" @@ -48,6 +49,7 @@ #include "ui/display/screen.h" #include "url/gurl.h" +using backdrop_wallpaper_handlers::SurpriseMeImageFetcher; using extension_misc::kWallpaperManagerId; namespace { @@ -636,6 +638,16 @@ storage_weak_factory_.GetWeakPtr(), task_runner)); } +void WallpaperControllerClientImpl::FetchDailyRefreshWallpaper( + const std::string& collection_id, + DailyWallpaperUrlFetchedCallback callback) { + surprise_me_image_fetcher_ = std::make_unique<SurpriseMeImageFetcher>( + collection_id, /*resume_token=*/std::string()); + surprise_me_image_fetcher_->Start( + base::BindOnce(&WallpaperControllerClientImpl::OnDailyImageInfoFetched, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + bool WallpaperControllerClientImpl::ShouldShowUserNamesOnLogin() const { bool show_user_names = true; ash::CrosSettings::Get()->GetBoolean( @@ -666,3 +678,16 @@ const std::string& collection_id) { wallpaper_controller_->SetDailyRefreshCollectionId(collection_id); } + +void WallpaperControllerClientImpl::OnDailyImageInfoFetched( + DailyWallpaperUrlFetchedCallback callback, + bool success, + const backdrop::Image& image, + const std::string& next_resume_token) { + if (success) { + std::move(callback).Run(image.image_url()); + } else { + std::move(callback).Run(std::string()); + } + surprise_me_image_fetcher_.reset(); +}
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h index b8d8fbf..83b8705 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h +++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
@@ -11,6 +11,7 @@ #include "ash/public/cpp/wallpaper_controller_client.h" #include "ash/public/cpp/wallpaper_types.h" #include "base/macros.h" +#include "chrome/browser/ash/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.h" #include "chrome/browser/ash/settings/cros_settings.h" #include "components/prefs/pref_change_registrar.h" #include "url/gurl.h" @@ -53,6 +54,9 @@ void SetDefaultWallpaper(const AccountId& account_id, bool show_wallpaper) override; void MigrateCollectionIdFromChromeApp() override; + void FetchDailyRefreshWallpaper( + const std::string& collection_id, + DailyWallpaperUrlFetchedCallback callback) override; // Wrappers around the ash::WallpaperController interface. void SetCustomWallpaper(const AccountId& account_id, @@ -144,6 +148,11 @@ // Passes |collection_id| to wallpaper controller on main task runner. void SetDailyRefreshCollectionId(const std::string& collection_id); + void OnDailyImageInfoFetched(DailyWallpaperUrlFetchedCallback callback, + bool success, + const backdrop::Image& image, + const std::string& next_resume_token); + // WallpaperController interface in ash. ash::WallpaperController* wallpaper_controller_; @@ -157,6 +166,9 @@ // wallpaper should be shown. base::CallbackListSubscription show_user_names_on_signin_subscription_; + std::unique_ptr<backdrop_wallpaper_handlers::SurpriseMeImageFetcher> + surprise_me_image_fetcher_; + base::WeakPtrFactory<WallpaperControllerClientImpl> weak_factory_{this}; base::WeakPtrFactory<WallpaperControllerClientImpl> storage_weak_factory_{ this};
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h index 70b55231..ab3912f 100644 --- a/chrome/browser/ui/browser_dialogs.h +++ b/chrome/browser/ui/browser_dialogs.h
@@ -22,6 +22,11 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/native_widget_types.h" +#if defined(OS_WIN) || defined(OS_MAC) || \ + (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +#include "chrome/browser/web_applications/components/web_app_id.h" +#endif + class Browser; class GURL; class LoginHandler; @@ -70,6 +75,13 @@ struct SelectedFileInfo; } // namespace ui +#if defined(OS_WIN) || defined(OS_MAC) || \ + (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +namespace web_app { +struct UrlHandlerLaunchParams; +} +#endif + namespace chrome { // Shows or hides the Task Manager. |browser| can be NULL when called from Ash. @@ -137,6 +149,25 @@ WebAppProtocolHandlerAcceptanceCallback close_callback); #endif +#if defined(OS_WIN) || defined(OS_MAC) || \ + (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +// Callback that runs when the Web App URL Handler Intent Picker dialog is +// closed. `accepted` is true when the dialog is accepted, false otherwise. +// `launch_params` contains information of the app that is selected to open by +// the user. It is null when the user selects to open the browser. +using WebAppUrlHandlerAcceptanceCallback = base::OnceCallback<void( + bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> launch_params)>; + +// Shows the Web App URL Handler Intent Picker dialog and runs +// `dialog_close_callback` on closure with the dialog acceptance status and +// information of the user-selected app. `launch_params_list` contains +// information of all the apps to show. +void ShowWebAppUrlHandlerIntentPickerDialog( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + WebAppUrlHandlerAcceptanceCallback dialog_close_callback); +#endif + // Sets whether |ShowWebAppDialog| should accept immediately without any // user interaction. |auto_open_in_window| sets whether the open in window // checkbox is checked.
diff --git a/chrome/browser/ui/caption_bubble_controller.h b/chrome/browser/ui/caption_bubble_controller.h index 9d79285..3780bf3b 100644 --- a/chrome/browser/ui/caption_bubble_controller.h +++ b/chrome/browser/ui/caption_bubble_controller.h
@@ -39,7 +39,7 @@ // Transcriptions will halt if this returns false. virtual bool OnTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, - const media::mojom::SpeechRecognitionResultPtr& result) = 0; + const media::SpeechRecognitionResult& result) = 0; // Called when the speech service has an error. virtual void OnError(LiveCaptionSpeechRecognitionHost*
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.cc b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.cc index f852b6d..b66476c 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.cc +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.cc
@@ -16,7 +16,10 @@ void SendTabToSelfToolbarButtonController::DisplayNewEntries( const std::vector<const SendTabToSelfEntry*>& new_entries) { - ShowToolbarButton(); + // TODO(crbug/1206381): Any entries that were never shown are lost. + // This is consistent with current behavior and we don't have UI for + // showing multiple entries with this iteration. + ShowToolbarButton(*new_entries.at(0)); } void SendTabToSelfToolbarButtonController::DismissEntries( @@ -24,14 +27,12 @@ NOTIMPLEMENTED(); } -void SendTabToSelfToolbarButtonController::ShowToolbarButton() { +void SendTabToSelfToolbarButtonController::ShowToolbarButton( + const SendTabToSelfEntry& entry) { if (!delegate_) return; - if (delegate_display_state_ != DisplayState::kShown) { - delegate_->Show(); - delegate_display_state_ = DisplayState::kShown; - } + delegate_->Show(entry); } void SendTabToSelfToolbarButtonController::SetDelegate( @@ -39,10 +40,6 @@ delegate_ = delegate; } -void SendTabToSelfToolbarButtonController::UpdateToolbarButtonState() { - NOTIMPLEMENTED(); -} - SendTabToSelfToolbarButtonController::~SendTabToSelfToolbarButtonController() = default;
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.h b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.h index ced31c4..c67462a 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.h +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.h
@@ -32,28 +32,16 @@ new_entries) override; void DismissEntries(const std::vector<std::string>& guids) override; - void ShowToolbarButton(); + void ShowToolbarButton(const SendTabToSelfEntry& entry); void SetDelegate(SendTabToSelfToolbarButtonControllerDelegate* delegate); Profile* profile() const { return profile_; } private: - // Tracks the current display state of the toolbar button delegate. - enum class DisplayState { - kShown, - kHidden, - }; - - void UpdateToolbarButtonState(); - Profile* profile_; SendTabToSelfToolbarButtonControllerDelegate* delegate_; - - // The delegate starts hidden and isn't shown until a STTS - // notification is received. - DisplayState delegate_display_state_ = DisplayState::kHidden; }; } // namespace send_tab_to_self
diff --git a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller_delegate.h b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller_delegate.h index 69f0643..734afa1 100644 --- a/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller_delegate.h +++ b/chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller_delegate.h
@@ -7,12 +7,13 @@ namespace send_tab_to_self { +class SendTabToSelfEntry; + // Delegate for SendTabToSelfToolbarButtonController that is told when to show // by the controller. class SendTabToSelfToolbarButtonControllerDelegate { public: - virtual void Show() = 0; - virtual void Hide() = 0; + virtual void Show(const SendTabToSelfEntry& entry) = 0; protected: virtual ~SendTabToSelfToolbarButtonControllerDelegate() = default;
diff --git a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc index ce8f4c0..2a30ffc 100644 --- a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc +++ b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc
@@ -8,7 +8,6 @@ #include "base/callback.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h" DiceWebSigninInterceptorDelegate::DiceWebSigninInterceptorDelegate() = default; @@ -32,24 +31,3 @@ Browser* browser) { ShowProfileCustomizationBubbleInternal(browser); } - -void DiceWebSigninInterceptorDelegate::ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) { - // TODO (crbug/1163117): Replace this temporary solution with the spaces - // enterprise welcome screen inside a dialog. - DiceTurnSyncOnHelper::Delegate::ShowEnterpriseAccountConfirmationForBrowser( - email, true, - base::BindOnce( - [](base::OnceCallback<void(bool)> callback, - DiceTurnSyncOnHelper::SigninChoice choice) { - std::move(callback).Run( - choice == DiceTurnSyncOnHelper::SigninChoice:: - SIGNIN_CHOICE_CONTINUE || - choice == DiceTurnSyncOnHelper::SigninChoice:: - SIGNIN_CHOICE_NEW_PROFILE); - }, - std::move(callback)), - browser); -}
diff --git a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h index 1b0be3bd..b796032 100644 --- a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h +++ b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.h
@@ -29,11 +29,6 @@ base::OnceCallback<void(SigninInterceptionResult)> callback) override; void ShowProfileCustomizationBubble(Browser* browser) override; - void ShowEnterpriseProfileInterceptionDialog( - const std::string& email, - base::OnceCallback<void(bool)> callback, - Browser* browser) override; - private: // Implemented in dice_web_signin_interception_bubble_view.cc std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle>
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 0d4fc22..dd91c15 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -470,6 +470,35 @@ } return false; } + +#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +bool MaybeLaunchUrlHandlerWebAppFromCmd( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + bool process_startup, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles) { + auto on_urls_unhandled_cb = base::BindOnce( + [](const base::CommandLine& command_line, const base::FilePath& cur_dir, + bool process_startup, Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles) { + // TODO(crbug.com/1208199): Refactor StartupBrowserCreator and use the + // state struct here. + StartupBrowserCreator startup_browser_creator; + startup_browser_creator.LaunchBrowserForLastProfiles( + command_line, cur_dir, process_startup, last_used_profile, + last_opened_profiles); + }, + command_line, cur_dir, process_startup, last_used_profile, + last_opened_profiles); + + return web_app::startup::MaybeLaunchUrlHandlerWebAppFromCmd( + command_line, cur_dir, last_used_profile, std::move(on_urls_unhandled_cb), + base::BindOnce(&FinalizeWebAppLaunch, + std::make_unique<LaunchModeRecorder>())); +} +#endif + } // namespace StartupBrowserCreator::StartupBrowserCreator() = default; @@ -573,6 +602,89 @@ return true; } +bool StartupBrowserCreator::LaunchBrowserForLastProfiles( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + bool process_startup, + Profile* last_used_profile, + const Profiles& last_opened_profiles) { + chrome::startup::IsProcessStartup is_process_startup = + process_startup ? chrome::startup::IS_PROCESS_STARTUP + : chrome::startup::IS_NOT_PROCESS_STARTUP; + chrome::startup::IsFirstRun is_first_run = + first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN + : chrome::startup::IS_NOT_FIRST_RUN; + + // On Windows, when chrome is launched by notification activation where the + // kNotificationLaunchId switch is used, always use |last_used_profile| which + // contains the profile id extracted from the notification launch id. + bool was_windows_notification_launch = false; +#if defined(OS_WIN) + was_windows_notification_launch = + command_line.HasSwitch(switches::kNotificationLaunchId); +#endif // defined(OS_WIN) + + // TODO(crbug.com/1150326) Calling ShouldShowProfilePickerAtProcessLaunch() + // a second time here duplicates the logic to show the profile picker. The + // decision to show the picker should instead be on the previous call to + // ShouldShowProfilePickerAtProcessLaunch() issued from + // GetStartupProfilePath(). + // Ephemeral guest is added here just for symmetry, once we use other ways to + // indicate that picker should get opened, we can remove both IsGuestSession() + // and IsEphemeralGuestProfile(). + if (ShouldShowProfilePickerAtProcessLaunch( + g_browser_process->profile_manager(), command_line) && + last_used_profile && + (last_used_profile->IsGuestSession() || + last_used_profile->IsEphemeralGuestProfile())) { + // The guest session is used to indicate the the profile picker should be + // displayed on start-up. See GetStartupProfilePath(). + ShowProfilePicker(/*is_process_startup=*/process_startup); + return true; + } + + // |last_opened_profiles| will be empty in the following circumstances: + // - This is the first launch. |last_used_profile| is the initial profile. + // - The user exited the browser by closing all windows for all profiles. + // |last_used_profile| is the profile which owned the last open window. + // - Only incognito windows were open when the browser exited. + // |last_used_profile| is the last used incognito profile. Restoring it will + // create a browser window for the corresponding original profile. + // - All of the last opened profiles fail to initialize. + if (last_opened_profiles.empty() || was_windows_notification_launch) { + if (CanOpenProfileOnStartup(last_used_profile)) { + Profile* profile_to_open = last_used_profile->IsGuestSession() + ? last_used_profile->GetPrimaryOTRProfile( + /*create_if_needed=*/true) + : last_used_profile; +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (process_startup) { + // If FullRestoreService is available for the profile (i.e. the full + // restore feature is enabled and the profile is a regular user + // profile), defer the browser launching to FullRestoreService code. + auto* full_restore_service = + chromeos::full_restore::FullRestoreService::GetForProfile( + profile_to_open); + if (full_restore_service) { + full_restore_service->LaunchBrowserWhenReady(); + return true; + } + } +#endif + return LaunchBrowser(command_line, profile_to_open, cur_dir, + is_process_startup, is_first_run, + std::make_unique<LaunchModeRecorder>()); + } + + // Show ProfilePicker if |last_used_profile| can't be auto opened. + ShowProfilePicker(/*is_process_startup=*/process_startup); + return true; + } + return ProcessLastOpenedProfiles(command_line, cur_dir, is_process_startup, + is_first_run, last_used_profile, + last_opened_profiles); +} + // static bool StartupBrowserCreator::WasRestarted() { // Stores the value of the preference kWasRestarted had when it was read. @@ -705,18 +817,18 @@ #endif // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) } +#if defined(OS_MAC) // static -bool StartupBrowserCreator::MaybeHandleProfileAgnosticUrls( - const std::vector<GURL>& urls) { +void StartupBrowserCreator::MaybeHandleProfileAgnosticUrls( + const std::vector<GURL>& urls, + base::OnceCallback<void()> on_urls_unhandled_cb) { // Web app URL handling. -#if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) - return web_app::startup::MaybeLaunchUrlHandlerWebAppFromUrls( - urls, base::BindOnce(&FinalizeWebAppLaunch, - std::make_unique<LaunchModeRecorder>())); -#endif - return false; + web_app::startup::MaybeLaunchUrlHandlerWebAppFromUrls( + urls, std::move(on_urls_unhandled_cb), + base::BindOnce(&FinalizeWebAppLaunch, + std::make_unique<LaunchModeRecorder>())); } +#endif // defined(OS_MAC) bool StartupBrowserCreator::ProcessCmdLineImpl( const base::CommandLine& command_line, @@ -1031,12 +1143,10 @@ } // Web app URL handling. -#if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) - if (web_app::startup::MaybeLaunchUrlHandlerWebAppFromCmd( - command_line, cur_dir, - base::BindOnce(&FinalizeWebAppLaunch, - std::make_unique<LaunchModeRecorder>()))) { +#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) + if (MaybeLaunchUrlHandlerWebAppFromCmd(command_line, cur_dir, process_startup, + last_used_profile, + last_opened_profiles)) { return true; } #endif @@ -1045,89 +1155,6 @@ last_used_profile, last_opened_profiles); } -bool StartupBrowserCreator::LaunchBrowserForLastProfiles( - const base::CommandLine& command_line, - const base::FilePath& cur_dir, - bool process_startup, - Profile* last_used_profile, - const Profiles& last_opened_profiles) { - chrome::startup::IsProcessStartup is_process_startup = - process_startup ? chrome::startup::IS_PROCESS_STARTUP - : chrome::startup::IS_NOT_PROCESS_STARTUP; - chrome::startup::IsFirstRun is_first_run = - first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN - : chrome::startup::IS_NOT_FIRST_RUN; - - // On Windows, when chrome is launched by notification activation where the - // kNotificationLaunchId switch is used, always use |last_used_profile| which - // contains the profile id extracted from the notification launch id. - bool was_windows_notification_launch = false; -#if defined(OS_WIN) - was_windows_notification_launch = - command_line.HasSwitch(switches::kNotificationLaunchId); -#endif // defined(OS_WIN) - - // TODO(crbug.com/1150326) Calling ShouldShowProfilePickerAtProcessLaunch() - // a second time here duplicates the logic to show the profile picker. The - // decision to show the picker should instead be on the previous call to - // ShouldShowProfilePickerAtProcessLaunch() issued from - // GetStartupProfilePath(). - // Ephemeral guest is added here just for symmetry, once we use other ways to - // indicate that picker should get opened, we can remove both IsGuestSession() - // and IsEphemeralGuestProfile(). - if (ShouldShowProfilePickerAtProcessLaunch( - g_browser_process->profile_manager(), command_line) && - last_used_profile && - (last_used_profile->IsGuestSession() || - last_used_profile->IsEphemeralGuestProfile())) { - // The guest session is used to indicate the the profile picker should be - // displayed on start-up. See GetStartupProfilePath(). - ShowProfilePicker(/*is_process_startup=*/process_startup); - return true; - } - - // |last_opened_profiles| will be empty in the following circumstances: - // - This is the first launch. |last_used_profile| is the initial profile. - // - The user exited the browser by closing all windows for all profiles. - // |last_used_profile| is the profile which owned the last open window. - // - Only incognito windows were open when the browser exited. - // |last_used_profile| is the last used incognito profile. Restoring it will - // create a browser window for the corresponding original profile. - // - All of the last opened profiles fail to initialize. - if (last_opened_profiles.empty() || was_windows_notification_launch) { - if (CanOpenProfileOnStartup(last_used_profile)) { - Profile* profile_to_open = last_used_profile->IsGuestSession() - ? last_used_profile->GetPrimaryOTRProfile( - /*create_if_needed=*/true) - : last_used_profile; -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (process_startup) { - // If FullRestoreService is available for the profile (i.e. the full - // restore feature is enabled and the profile is a regular user - // profile), defer the browser launching to FullRestoreService code. - auto* full_restore_service = - chromeos::full_restore::FullRestoreService::GetForProfile( - profile_to_open); - if (full_restore_service) { - full_restore_service->LaunchBrowserWhenReady(); - return true; - } - } -#endif - return LaunchBrowser(command_line, profile_to_open, cur_dir, - is_process_startup, is_first_run, - std::make_unique<LaunchModeRecorder>()); - } - - // Show ProfilePicker if |last_used_profile| can't be auto opened. - ShowProfilePicker(/*is_process_startup=*/process_startup); - return true; - } - return ProcessLastOpenedProfiles(command_line, cur_dir, is_process_startup, - is_first_run, last_used_profile, - last_opened_profiles); -} - bool StartupBrowserCreator::ProcessLastOpenedProfiles( const base::CommandLine& command_line, const base::FilePath& cur_dir,
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index a288b33..c348a48 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" +#include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" @@ -93,6 +94,15 @@ chrome::startup::IsFirstRun is_first_run, std::unique_ptr<LaunchModeRecorder> launch_mode_recorder); + // Launch browser for `last_opened_profiles` if it's not empty. Otherwise, + // launch browser for `last_used_profile`. Return false if any browser is + // failed to be launched. Otherwise, return true. + bool LaunchBrowserForLastProfiles(const base::CommandLine& command_line, + const base::FilePath& cur_dir, + bool process_startup, + Profile* last_used_profile, + const Profiles& last_opened_profiles); + // If Incognito or Guest mode are requested by policy or command line returns // the appropriate private browsing profile. Otherwise returns |profile|. Profile* GetPrivateProfileIfRequested(const base::CommandLine& command_line, @@ -113,8 +123,14 @@ static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); static void RegisterProfilePrefs(PrefRegistrySimple* registry); - // Return true if |urls| are handled, false otherwise. - static bool MaybeHandleProfileAgnosticUrls(const std::vector<GURL>& urls); +#if defined(OS_MAC) + // Searches for web apps to handle `urls` and prompts the user to pick one. + // Runs `on_urls_unhandled_cb` (either synchronously or asynchronously) if no + // web app is found or selected to open `urls`. + static void MaybeHandleProfileAgnosticUrls( + const std::vector<GURL>& urls, + base::OnceClosure on_urls_unhandled_cb); +#endif private: friend class CloudPrintProxyPolicyTest; @@ -153,15 +169,6 @@ Profile* last_used_profile, const Profiles& last_opened_profiles); - // Launch browser for |last_opened_profiles| if it's not empty. Otherwise, - // launch browser for |last_used_profile|. Return false if any browser is - // failed to be launched. Otherwise, return true. - bool LaunchBrowserForLastProfiles(const base::CommandLine& command_line, - const base::FilePath& cur_dir, - bool process_startup, - Profile* last_used_profile, - const Profiles& last_opened_profiles); - // Launch the |last_used_profile| with the full command line, and the other // |last_opened_profiles| without the URLs to launch. Return false if any // browser is failed to be launched. Otherwise, return true.
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 73711f1..e5f8a590 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -120,7 +120,11 @@ #include "chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "components/services/app_service/public/cpp/url_handler_info.h" +#include "extensions/browser/extension_dialog_auto_confirm.h" #include "third_party/blink/public/common/features.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" #endif using testing::Return; @@ -269,6 +273,15 @@ std::move(quit_closure_).Run(); } +#if defined(OS_WIN) || defined(OS_MAC) || \ + (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) +void AutoCloseDialog(views::Widget* widget) { + // Call CancelDialog to close the dialog, but the actual behavior will be + // determined by the ScopedTestDialogAutoConfirm configs. + views::test::CancelDialog(widget); +} +#endif + } // namespace class StartupBrowserCreatorTest : public extensions::ExtensionBrowserTest { @@ -1665,14 +1678,73 @@ }; IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppUrlHandlingTest, - WebAppLaunch_InScopeUrl) { + DialogCancelled_NoLaunch) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); + apps::UrlHandlerInfo url_handler; url_handler.origin = url::Origin::Create(GURL(kStartUrl)); web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + SetUpCommandlineAndStart(kStartUrl); + + // The waiter will get the dialog when it shows up and close it. + waiter.WaitIfNeededAndGet()->CloseWithReason( + views::Widget::ClosedReason::kEscKeyPressed); + + // Wait for browser launch task to complete. + content::RunAllTasksUntilIdle(); + + // When dialog is closed, nothing will happen. + ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); + ASSERT_FALSE(web_app::AppBrowserController::IsForWebApp(browser(), app_id)); +} + +IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppUrlHandlingTest, + DialogAccepted_BrowserLaunch) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); + + apps::UrlHandlerInfo url_handler; + url_handler.origin = url::Origin::Create(GURL(kStartUrl)); + + web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + + // Select the first choice, which is the browser. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 0); + SetUpCommandlineAndStart(kStartUrl); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); + + // Wait for browser launch task to complete. + content::RunAllTasksUntilIdle(); + + // When dialog is closed, URL will be launched in a browser window. + // Check for new browser window. + ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); + ASSERT_FALSE(web_app::AppBrowserController::IsForWebApp(browser(), app_id)); + Browser* other_browser = FindOneOtherBrowser(browser()); + ASSERT_TRUE(other_browser); + ASSERT_FALSE( + web_app::AppBrowserController::IsForWebApp(other_browser, app_id)); +} + +IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppUrlHandlingTest, + DialogAccepted_WebAppLaunch_InScopeUrl) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); + apps::UrlHandlerInfo url_handler; + url_handler.origin = url::Origin::Create(GURL(kStartUrl)); + + web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + + // Select the second choice, which is the app. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 1); // kStartUrl is in app scope. SetUpCommandlineAndStart(kStartUrl); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); // Wait for app launch task to complete. content::RunAllTasksUntilIdle(); @@ -1691,13 +1763,19 @@ } IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppUrlHandlingTest, - WebAppLaunch_DifferentOriginUrl) { + DialogAccepted_WebAppLaunch_DifferentOriginUrl) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppUrlHandlerIntentPickerView"); apps::UrlHandlerInfo url_handler; url_handler.origin = url::Origin::Create(GURL("https://example.com")); web_app::AppId app_id = InstallWebAppWithUrlHandlers({url_handler}); + // Select the second choice, which is the app. + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 1); // URL is not in app scope but matches url_handlers of installed app. SetUpCommandlineAndStart("https://example.com/abc/def"); + AutoCloseDialog(waiter.WaitIfNeededAndGet()); // Wait for app launch task to complete. content::RunAllTasksUntilIdle();
diff --git a/chrome/browser/ui/startup/web_app_url_handling_startup_utils.cc b/chrome/browser/ui/startup/web_app_url_handling_startup_utils.cc index b6f8a9b..9423419c 100644 --- a/chrome/browser/ui/startup/web_app_url_handling_startup_utils.cc +++ b/chrome/browser/ui/startup/web_app_url_handling_startup_utils.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/startup/web_app_url_handling_startup_utils.h" +#include <algorithm> #include <utility> #include <vector> @@ -13,9 +14,15 @@ #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/first_run/first_run.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/startup/startup_browser_creator.h" +#include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/browser/web_applications/components/url_handler_launch_params.h" #include "chrome/browser/web_applications/components/url_handler_manager_impl.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -37,37 +44,41 @@ std::move(callback)); } -bool LaunchFirstValidMatch( +void OnUrlHandlerIntentPickerDialogCompleted( const base::CommandLine& command_line, const base::FilePath& cur_dir, - const std::vector<web_app::UrlHandlerLaunchParams>& url_handler_matches, - web_app::startup::FinalizeWebAppLaunchCallback callback) { - // Launch the first match for which a Profile can be loaded. - // TODO(crbug/1072058): Use WebAppUiManagerImpl and WebAppDialogManager - // to display the intent picker dialog. Use the first match here for testing. - // TODO(crbug/1072058): Check user preferences before showing intent picker. - ProfileManager* profile_manager = g_browser_process->profile_manager(); - Profile* profile = nullptr; - const web_app::UrlHandlerLaunchParams* found_match = nullptr; - for (const auto& match : url_handler_matches) { - // Do not load profile if profile path is not valid. - if (!profile_manager->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(match.profile_path)) { - continue; - } - profile = profile_manager->GetProfile(match.profile_path); - if (profile) { - found_match = &match; - break; - } - } + base::OnceClosure on_urls_unhandled_cb, + web_app::startup::FinalizeWebAppLaunchCallback app_launched_callback, + bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> selected_match) { + // Dialog is not accepted. Quit the process and do nothing. + if (!accepted) + return; - if (profile && found_match) { - LaunchApp(found_match->profile_path, found_match->app_id, command_line, - cur_dir, found_match->url, std::move(callback)); - return true; + if (selected_match.has_value()) { + // The user has selected an app to handle the URL. + LaunchApp(selected_match->profile_path, selected_match->app_id, + command_line, cur_dir, selected_match->url, + std::move(app_launched_callback)); + } else { + // The user has selected the browser. Open the link in the browser. + std::move(on_urls_unhandled_cb).Run(); } - return false; +} + +std::vector<web_app::UrlHandlerLaunchParams> GetValidUrlHandlerMatches( + std::vector<web_app::UrlHandlerLaunchParams> url_handler_matches, + const base::FilePath& last_used_profile) { + // TODO(crbug.com/1200951): Save matches from all valid profiles, not just + // the last used profile. + url_handler_matches.erase( + std::remove_if( + url_handler_matches.begin(), url_handler_matches.end(), + [&last_used_profile](const web_app::UrlHandlerLaunchParams& match) { + return match.profile_path != last_used_profile; + }), + url_handler_matches.end()); + return url_handler_matches; } } // namespace @@ -75,25 +86,51 @@ namespace web_app { namespace startup { -bool MaybeLaunchUrlHandlerWebAppFromCmd(const base::CommandLine& command_line, - const base::FilePath& cur_dir, - FinalizeWebAppLaunchCallback callback) { - return LaunchFirstValidMatch( - command_line, cur_dir, +bool MaybeLaunchUrlHandlerWebAppFromCmd( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* last_used_profile, + base::OnceClosure on_urls_unhandled_cb, + FinalizeWebAppLaunchCallback app_launched_callback) { + auto valid_matches = GetValidUrlHandlerMatches( UrlHandlerManagerImpl::GetUrlHandlerMatches(command_line), - std::move(callback)); -} - -bool MaybeLaunchUrlHandlerWebAppFromUrls( - const std::vector<GURL>& urls, - FinalizeWebAppLaunchCallback callback) { - if (urls.size() != 1) + last_used_profile->GetPath()); + if (valid_matches.empty()) return false; - return LaunchFirstValidMatch( - base::CommandLine(base::CommandLine::NO_PROGRAM), base::FilePath(), + chrome::ShowWebAppUrlHandlerIntentPickerDialog( + std::move(valid_matches), + base::BindOnce(&OnUrlHandlerIntentPickerDialogCompleted, command_line, + cur_dir, std::move(on_urls_unhandled_cb), + std::move(app_launched_callback))); + return true; +} + +void MaybeLaunchUrlHandlerWebAppFromUrls( + const std::vector<GURL>& urls, + base::OnceClosure on_urls_unhandled_cb, + FinalizeWebAppLaunchCallback app_launched_callback) { + if (urls.size() != 1 || !g_browser_process->profile_manager()) { + std::move(on_urls_unhandled_cb).Run(); + return; + } + + auto valid_matches = GetValidUrlHandlerMatches( UrlHandlerManagerImpl::GetUrlHandlerMatches(urls.front()), - std::move(callback)); + g_browser_process->profile_manager() + ->GetLastUsedProfileAllowedByPolicy() + ->GetPath()); + if (valid_matches.empty()) { + std::move(on_urls_unhandled_cb).Run(); + return; + } + + chrome::ShowWebAppUrlHandlerIntentPickerDialog( + std::move(valid_matches), + base::BindOnce(&OnUrlHandlerIntentPickerDialogCompleted, + base::CommandLine(base::CommandLine::NO_PROGRAM), + base::FilePath(), std::move(on_urls_unhandled_cb), + std::move(app_launched_callback))); } } // namespace startup
diff --git a/chrome/browser/ui/startup/web_app_url_handling_startup_utils.h b/chrome/browser/ui/startup/web_app_url_handling_startup_utils.h index 56f383c..2d968285 100644 --- a/chrome/browser/ui/startup/web_app_url_handling_startup_utils.h +++ b/chrome/browser/ui/startup/web_app_url_handling_startup_utils.h
@@ -17,6 +17,7 @@ class Browser; class GURL; +class Profile; namespace web_app { namespace startup { @@ -25,18 +26,24 @@ base::OnceCallback<void(Browser* browser, apps::mojom::LaunchContainer container)>; -// If |command_line| contains a single URL argument and that URL matches URL +// If `command_line` contains a single URL argument and that URL matches URL // handling registration from installed web apps, show app options to user and // launch one if accepted. -// Returns true if launching an app, false otherwise. -bool MaybeLaunchUrlHandlerWebAppFromCmd(const base::CommandLine& command_line, - const base::FilePath& cur_dir, - FinalizeWebAppLaunchCallback callback); +// Returns true if matching web apps are found, false otherwise. +bool MaybeLaunchUrlHandlerWebAppFromCmd( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* last_used_profile, + base::OnceClosure on_urls_unhandled_cb, + FinalizeWebAppLaunchCallback app_launched_callback); -// Same as MaybeLaunchUrlHandlerWebAppFromCmd but check if |urls| contains a -// single URL. -bool MaybeLaunchUrlHandlerWebAppFromUrls(const std::vector<GURL>& urls, - FinalizeWebAppLaunchCallback callback); +// Checks if `urls` contains a single URL that can be handled by installed web +// app URL handlers, show app options to user and launch one if accepted. +// Otherwise, run `on_urls_unhandled_cb` to open `urls` in the browser. +void MaybeLaunchUrlHandlerWebAppFromUrls( + const std::vector<GURL>& urls, + base::OnceClosure on_urls_unhandled_cb, + FinalizeWebAppLaunchCallback app_launched_callback); } // namespace startup } // namespace web_app
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper_browsertest.cc b/chrome/browser/ui/thumbnails/thumbnail_tab_helper_browsertest.cc index 2a4809e..b0292b0c 100644 --- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper_browsertest.cc +++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper_browsertest.cc
@@ -167,10 +167,17 @@ // with ENABLE_SESSION_SERVICE. #if BUILDFLAG(ENABLE_SESSION_SERVICE) +// Flaky on Win: https://crbug.com/1211377 +#if defined(OS_WIN) +#define MAYBE_CapturesRestoredTabWhenRequested \ + DISABLED_CapturesRestoredTabWhenRequested +#else +#define MAYBE_CapturesRestoredTabWhenRequested CapturesRestoredTabWhenRequested +#endif // On browser restore, some tabs may not be loaded. Requesting a // thumbnail for one of these tabs should trigger load and capture. IN_PROC_BROWSER_TEST_F(ThumbnailTabHelperBrowserTest, - CapturesRestoredTabWhenRequested) { + MAYBE_CapturesRestoredTabWhenRequested) { ui_test_utils::NavigateToURLWithDisposition( browser(), url2_, WindowOpenDisposition::NEW_WINDOW, ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
diff --git a/chrome/browser/ui/user_education/README.md b/chrome/browser/ui/user_education/README.md new file mode 100644 index 0000000..5abb46b --- /dev/null +++ b/chrome/browser/ui/user_education/README.md
@@ -0,0 +1,16 @@ +# Desktop User Education + +This directory contains code related to user education efforts on desktop. Also +see [//chrome/browser/ui/views/user_education](../views/user_education) + +Active projects: +* In-product help (IPH): help dialogs offered by Chrome suggesting useful + features. These are triggered automatically based on user behavior and give a + short value statement and directions to use the feature +* New badge: pop-out label applied to new features' entry points to make them + more obvious +* Tutorials: step-by-step guided walkthroughs of features. User-initiated and + more thorough than single-step IPH promotions + +TODO(https://crbug.com/1132335): add overview and thorough instructions on how +to apply user education to features
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 54d97ad..5b39156 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.cc
@@ -47,7 +47,7 @@ bool CaptionBubbleControllerViews::OnTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, - const media::mojom::SpeechRecognitionResultPtr& result) { + const media::SpeechRecognitionResult& result) { if (!caption_bubble_) return false; SetActiveModel(live_caption_speech_recognition_host); @@ -59,11 +59,11 @@ // transcription after several seconds of no audio. This prevents the bubble // reappearing with a final transcription after it had disappeared due to no // activity. - if (!caption_bubble_->HasActivity() && result->is_final) + if (!caption_bubble_->HasActivity() && result.is_final) return true; - active_model_->SetPartialText(result->transcription); - if (result->is_final) + active_model_->SetPartialText(result.transcription); + if (result.is_final) active_model_->CommitPartialText(); return true;
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 061bb2a2..911c2ee 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views.h
@@ -42,7 +42,7 @@ // Transcriptions will halt if this returns false. bool OnTranscription( LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host, - const media::mojom::SpeechRecognitionResultPtr& result) override; + const media::SpeechRecognitionResult& result) override; // Called when the speech service has an error. void OnError(LiveCaptionSpeechRecognitionHost*
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 a7e5dc8..1e02fea 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
@@ -149,7 +149,7 @@ LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { return GetController()->OnTranscription( live_caption_speech_recognition_host, - media::mojom::SpeechRecognitionResult::New(text, false)); + media::SpeechRecognitionResult(text, false)); } bool OnFinalTranscription(std::string text) { @@ -161,7 +161,7 @@ LiveCaptionSpeechRecognitionHost* live_caption_speech_recognition_host) { return GetController()->OnTranscription( live_caption_speech_recognition_host, - media::mojom::SpeechRecognitionResult::New(text, true)); + media::SpeechRecognitionResult(text, true)); } void OnError() { OnError(GetLiveCaptionSpeechRecognitionHost()); }
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc index 8b63d88..43286ac 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -615,7 +615,7 @@ /*vertical=*/0, /*horizontal=*/ ChromeLayoutProvider::Get()->GetDistanceMetric( - views::DISTANCE_RELATED_LABEL_HORIZONTAL))); + DISTANCE_RELATED_LABEL_HORIZONTAL_LIST))); first_line_container->AddChildView(std::move(main_text_label)); first_line_container->AddChildView(std::move(minor_text_label));
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.cc b/chrome/browser/ui/views/borealis/borealis_installer_view.cc index 5078f39..c776ef2 100644 --- a/chrome/browser/ui/views/borealis/borealis_installer_view.cc +++ b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
@@ -12,8 +12,10 @@ #include "base/callback_helpers.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/borealis/borealis_app_launcher.h" #include "chrome/browser/ash/borealis/borealis_context_manager.h" #include "chrome/browser/ash/borealis/borealis_installer.h" +#include "chrome/browser/ash/borealis/borealis_metrics.h" #include "chrome/browser/ash/borealis/borealis_service.h" #include "chrome/browser/ash/borealis/borealis_util.h" #include "chrome/browser/ui/browser_navigator.h" @@ -72,8 +74,8 @@ METADATA_HEADER(TitleLabel); - TitleLabel() {} - ~TitleLabel() override {} + TitleLabel() = default; + ~TitleLabel() override = default; void GetAccessibleNodeData(ui::AXNodeData* node_data) override { node_data->SetName(GetText()); @@ -202,9 +204,14 @@ if (state_ == State::kCompleted) { // Launch button has been clicked. - borealis::BorealisService::GetForProfile(profile_) - ->ContextManager() - .StartBorealis(base::DoNothing()); + borealis::BorealisService::GetForProfile(profile_)->AppLauncher().Launch( + borealis::kBorealisMainAppId, + base::BindOnce([](borealis::BorealisAppLauncher::LaunchResult result) { + if (result == borealis::BorealisAppLauncher::LaunchResult::kSuccess) + return; + LOG(ERROR) << "Failed to launch borealis after install: code=" + << static_cast<int>(result); + })); return true; } @@ -216,6 +223,17 @@ } bool BorealisInstallerView::Cancel() { + if (state_ == State::kCompleted) { + borealis::BorealisService::GetForProfile(profile_) + ->ContextManager() + .ShutDownBorealis( + base::BindOnce([](borealis::BorealisShutdownResult result) { + if (result == borealis::BorealisShutdownResult::kSuccess) + return; + LOG(ERROR) << "Failed to shutdown borealis after install: code=" + << static_cast<int>(result); + })); + } return true; } @@ -350,6 +368,8 @@ case borealis::BorealisInstallResult::kBorealisNotAllowed: case borealis::BorealisInstallResult::kDlcUnsupportedError: case borealis::BorealisInstallResult::kDlcNeedUpdateError: + case borealis::BorealisInstallResult::kStartupFailed: + case borealis::BorealisInstallResult::kMainAppNotPresent: return ui::DIALOG_BUTTON_CANCEL; case borealis::BorealisInstallResult::kBorealisInstallInProgress: case borealis::BorealisInstallResult::kDlcInternalError:
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc index fa2fac8..0cdc5a0 100644 --- a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc +++ b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
@@ -4,19 +4,28 @@ #include "chrome/browser/ui/views/borealis/borealis_installer_view.h" +#include <memory> + #include "base/bind.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ash/borealis/borealis_app_launcher.h" #include "chrome/browser/ash/borealis/borealis_context.h" #include "chrome/browser/ash/borealis/borealis_context_manager_mock.h" +#include "chrome/browser/ash/borealis/borealis_features.h" #include "chrome/browser/ash/borealis/borealis_installer.h" #include "chrome/browser/ash/borealis/borealis_metrics.h" +#include "chrome/browser/ash/borealis/borealis_prefs.h" +#include "chrome/browser/ash/borealis/borealis_service.h" #include "chrome/browser/ash/borealis/borealis_service_fake.h" #include "chrome/browser/ash/borealis/borealis_task.h" #include "chrome/browser/ash/borealis/borealis_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" #include "chromeos/dbus/dbus_thread_manager.h" +#include "components/prefs/pref_service.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -45,16 +54,23 @@ class BorealisInstallerViewBrowserTest : public DialogBrowserTest { public: - BorealisInstallerViewBrowserTest() = default; + BorealisInstallerViewBrowserTest() { + feature_list_.InitAndEnableFeature(features::kBorealis); + } // DialogBrowserTest: void SetUpOnMainThread() override { app_name_ = l10n_util::GetStringUTF16(IDS_BOREALIS_APP_NAME); + app_launcher_ = std::make_unique<BorealisAppLauncher>(browser()->profile()); + features_ = std::make_unique<BorealisFeatures>(browser()->profile()); + BorealisServiceFake* fake_service = BorealisServiceFake::UseFakeForTesting(browser()->profile()); fake_service->SetContextManagerForTesting(&mock_context_manager_); fake_service->SetInstallerForTesting(&mock_installer_); + fake_service->SetAppLauncherForTesting(app_launcher_.get()); + fake_service->SetFeaturesForTesting(features_.get()); } void ShowUi(const std::string& name) override { @@ -126,8 +142,11 @@ EXPECT_TRUE(view_->GetWidget()->IsClosed()); } + base::test::ScopedFeatureList feature_list_; ::testing::StrictMock<BorealisInstallerMock> mock_installer_; ::testing::StrictMock<BorealisContextManagerMock> mock_context_manager_; + std::unique_ptr<BorealisAppLauncher> app_launcher_; + std::unique_ptr<BorealisFeatures> features_; BorealisInstallerView* view_; std::u16string app_name_; @@ -150,9 +169,13 @@ ShowUi("default"); AcceptInstallation(); + browser()->profile()->GetPrefs()->SetBoolean( + prefs::kBorealisInstalledOnDevice, true); view_->OnInstallationEnded(InstallationResult::kSuccess); ExpectInstallationCompletedSucessfully(); + EXPECT_CALL(mock_context_manager_, IsRunning()) + .WillOnce(testing::Return(true)); EXPECT_CALL(mock_context_manager_, StartBorealis(_)); EXPECT_CALL(mock_installer_, RemoveObserver(_)); view_->AcceptDialog(); @@ -192,9 +215,13 @@ AcceptInstallation(); + browser()->profile()->GetPrefs()->SetBoolean( + prefs::kBorealisInstalledOnDevice, true); view_->OnInstallationEnded(InstallationResult::kSuccess); ExpectInstallationCompletedSucessfully(); + EXPECT_CALL(mock_context_manager_, IsRunning()) + .WillOnce(testing::Return(true)); EXPECT_CALL(mock_context_manager_, StartBorealis(_)); EXPECT_CALL(mock_installer_, RemoveObserver(_)); view_->AcceptDialog();
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_permission_view.cc b/chrome/browser/ui/views/file_system_access/file_system_access_permission_view.cc index a7cfb60f..82b87ba 100644 --- a/chrome/browser/ui/views/file_system_access/file_system_access_permission_view.cc +++ b/chrome/browser/ui/views/file_system_access/file_system_access_permission_view.cc
@@ -6,6 +6,7 @@ #include "base/files/file_path.h" #include "base/memory/ptr_util.h" +#include "chrome/browser/file_system_access/chrome_file_system_access_permission_context.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/file_system_access/file_system_access_ui_helpers.h" @@ -29,16 +30,30 @@ int GetMessageText(const FileSystemAccessPermissionView::Request& request) { switch (request.access) { case AccessType::kRead: - return request.handle_type == HandleType::kDirectory - ? IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_READ_PERMISSION_DIRECTORY_TEXT - : IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_READ_PERMISSION_FILE_TEXT; + if (base::FeatureList::IsEnabled( + features::kFileSystemAccessPersistentPermissions)) { + return request.handle_type == HandleType::kDirectory + ? IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_DIRECTORY_TEXT + : IDS_FILE_SYSTEM_ACCESS_READ_PERMISSION_FILE_TEXT; + } else { + return request.handle_type == HandleType::kDirectory + ? IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_READ_PERMISSION_DIRECTORY_TEXT + : IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_READ_PERMISSION_FILE_TEXT; + } case AccessType::kWrite: case AccessType::kReadWrite: // Only difference between write and read-write access dialog is in button // label and dialog title. - return request.handle_type == HandleType::kDirectory - ? IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_WRITE_PERMISSION_DIRECTORY_TEXT - : IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_WRITE_PERMISSION_FILE_TEXT; + if (base::FeatureList::IsEnabled( + features::kFileSystemAccessPersistentPermissions)) { + return request.handle_type == HandleType::kDirectory + ? IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_DIRECTORY_TEXT + : IDS_FILE_SYSTEM_ACCESS_WRITE_PERMISSION_FILE_TEXT; + } else { + return request.handle_type == HandleType::kDirectory + ? IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_WRITE_PERMISSION_DIRECTORY_TEXT + : IDS_FILE_SYSTEM_ACCESS_ORIGIN_SCOPED_WRITE_PERMISSION_FILE_TEXT; + } } NOTREACHED(); }
diff --git a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller_browsertest.cc index c130356..0946535 100644 --- a/chrome/browser/ui/views/payments/shipping_address_editor_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/shipping_address_editor_view_controller_browsertest.cc
@@ -621,8 +621,14 @@ request->state()->selected_shipping_option_error_profile()); } +// Flaky on ozone: https://crbug.com/1216184 +#if defined(USE_OZONE) +#define MAYBE_FocusFirstField_Name DISABLED_FocusFirstField_Name +#else +#define MAYBE_FocusFirstField_Name FocusFirstField_Name +#endif IN_PROC_BROWSER_TEST_F(MAYBE_PaymentRequestShippingAddressEditorTest, - FocusFirstField_Name) { + MAYBE_FocusFirstField_Name) { NavigateTo("/payment_request_dynamic_shipping_test.html"); InvokePaymentRequestUI(); SetRegionDataLoader(&test_region_data_loader_); @@ -644,8 +650,15 @@ EXPECT_TRUE(textfield->HasFocus()); } +// Flaky on ozone: https://crbug.com/1216184 +#if defined(USE_OZONE) +#define MAYBE_FocusFirstInvalidField_NotName \ + DISABLED_FocusFirstInvalidField_NotName +#else +#define MAYBE_FocusFirstInvalidField_NotName FocusFirstInvalidField_NotName +#endif IN_PROC_BROWSER_TEST_F(MAYBE_PaymentRequestShippingAddressEditorTest, - FocusFirstInvalidField_NotName) { + MAYBE_FocusFirstInvalidField_NotName) { NavigateTo("/payment_request_dynamic_shipping_test.html"); // Add address with only the name set, so that another view takes focus. autofill::AutofillProfile profile;
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc index 19914106..0ec690d 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc
@@ -143,8 +143,15 @@ } #endif +// Flaky on Mac, see https://crbug.com/1216134 +#if defined(OS_MAC) +#define MAYBE_FullscreenWithKeyboard DISABLED_FullscreenWithKeyboard +#else +#define MAYBE_FullscreenWithKeyboard FullscreenWithKeyboard +#endif // Checks that the main picker view can switch to full screen. -IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, FullscreenWithKeyboard) { +IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, + MAYBE_FullscreenWithKeyboard) { // Open a new picker. ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles); WaitForLayoutWithoutToolbar();
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index c4ffeff..e9f02d26 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "base/util/values/values_util.h" +#include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/feature_engagement/tracker_factory.h" #include "chrome/browser/policy/cloud/user_policy_signin_service.h" @@ -939,8 +940,14 @@ /*enable_feature=*/false) {} }; +// Flaky on Win: https://crbug.com/1215038 +#if defined(OS_WIN) +#define MAYBE_CreateSignedInProfile DISABLED_CreateSignedInProfile +#else +#define MAYBE_CreateSignedInProfile CreateSignedInProfile +#endif IN_PROC_BROWSER_TEST_F(ProfilePickerSeparateEnterpriseCreationFlowBrowserTest, - CreateSignedInProfile) { + MAYBE_CreateSignedInProfile) { ASSERT_EQ(1u, BrowserList::GetInstance()->size()); Profile* profile_being_created = StartSigninFlow();
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.cc new file mode 100644 index 0000000..d51943b5 --- /dev/null +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.cc
@@ -0,0 +1,117 @@ +// 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/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h" + +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h" +#include "chrome/grit/generated_resources.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/layout/flex_layout.h" +#include "ui/views/layout/flex_layout_types.h" + +namespace send_tab_to_self { + +// static +SendTabToSelfToolbarBubbleView* SendTabToSelfToolbarBubbleView::CreateBubble( + Profile* profile, + SendTabToSelfToolbarButtonView* parent, + const SendTabToSelfEntry& entry, + base::OnceCallback<void(NavigateParams*)> navigate_callback) { + SendTabToSelfToolbarBubbleView* bubble_view = + new SendTabToSelfToolbarBubbleView(profile, parent, entry, + std::move(navigate_callback)); + // The widget is owned by the views system. + views::Widget* widget = + views::BubbleDialogDelegateView::CreateBubble(bubble_view); + widget->Show(); + return bubble_view; +} + +SendTabToSelfToolbarBubbleView::~SendTabToSelfToolbarBubbleView() = default; + +SendTabToSelfToolbarBubbleView::SendTabToSelfToolbarBubbleView( + Profile* profile, + SendTabToSelfToolbarButtonView* parent, + const SendTabToSelfEntry& entry, + base::OnceCallback<void(NavigateParams*)> navigate_callback) + : views::BubbleDialogDelegateView(dynamic_cast<views::View*>(parent), + views::BubbleBorder::TOP_RIGHT), + toolbar_button_(parent), + navigate_callback_(std::move(navigate_callback)), + profile_(profile), + title_(entry.GetTitle()), + url_(entry.GetURL()), + device_name_(entry.GetDeviceName()), + guid_(entry.GetGUID()) { + SetButtons(ui::DIALOG_BUTTON_NONE); + SetShowCloseButton(true); + SetTitle( + l10n_util::GetStringUTF16(IDS_TOOLBAR_BUTTON_SEND_TAB_TO_SELF_TITLE)); + SetCloseCallback(base::BindOnce(&SendTabToSelfToolbarBubbleView::Hide, + base::Unretained(this))); + set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUBBLE_PREFERRED_WIDTH)); + set_close_on_deactivate(false); + + SetLayoutManager(std::make_unique<views::FlexLayout>()) + ->SetOrientation(views::LayoutOrientation::kVertical) + .SetCrossAxisAlignment(views::LayoutAlignment::kStart); + + // TODO(crbug/1206381): Check formatting against spec, fix text eliding, add + // metrics. + + // Page title. + auto title = std::make_unique<views::Label>(base::UTF8ToUTF16(title_)); + title->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + title->SetTextStyle(views::style::STYLE_PRIMARY); + title->SetElideBehavior(gfx::ELIDE_TAIL); + AddChildView(std::move(title)); + + // Page URL. + auto url = std::make_unique<views::Label>(base::UTF8ToUTF16(url_.spec())); + url->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + url->SetTextStyle(views::style::STYLE_SECONDARY); + url->SetElideBehavior(gfx::ELIDE_TAIL); + AddChildView(std::move(url)); + + // Device name. + auto device = std::make_unique<views::Label>(l10n_util::GetStringFUTF16( + IDS_TOOLBAR_BUTTON_SEND_TAB_TO_SELF_FROM_DEVICE, + base::UTF8ToUTF16(device_name_))); + device->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + device->SetTextStyle(views::style::STYLE_SECONDARY); + device->SetElideBehavior(gfx::ELIDE_TAIL); + AddChildView(std::move(device)); + + // Open in New Tab button. + auto button = std::make_unique<views::MdTextButton>( + base::BindRepeating(&SendTabToSelfToolbarBubbleView::OpenInNewTab, + base::Unretained(this)), + l10n_util::GetStringUTF16( + IDS_TOOLBAR_BUTTON_SEND_TAB_TO_SELF_BUTTON_LABEL)); + button->SetProminent(true); + button->SetProperty(views::kCrossAxisAlignmentKey, + views::LayoutAlignment::kEnd); + AddChildView(std::move(button)); +} + +void SendTabToSelfToolbarBubbleView::OpenInNewTab() { + NavigateParams params(profile_, url_, ui::PAGE_TRANSITION_LINK); + params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; + params.window_action = NavigateParams::SHOW_WINDOW; + std::move(navigate_callback_).Run(¶ms); + + GetWidget()->Close(); +} + +void SendTabToSelfToolbarBubbleView::Hide() { + toolbar_button_->DismissEntry(guid_); +} + +} // namespace send_tab_to_self
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h new file mode 100644 index 0000000..dcbcb7d --- /dev/null +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h
@@ -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. + +#ifndef CHROME_BROWSER_UI_VIEWS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_TOOLBAR_BUBBLE_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_TOOLBAR_BUBBLE_VIEW_H_ + +#include "ui/views/bubble/bubble_dialog_delegate_view.h" + +class Profile; +struct NavigateParams; + +namespace send_tab_to_self { + +class SendTabToSelfEntry; +class SendTabToSelfToolbarButtonView; + +class SendTabToSelfToolbarBubbleView : public views::BubbleDialogDelegateView { + public: + ~SendTabToSelfToolbarBubbleView() override; + + // Creates and shows the bubble. + static SendTabToSelfToolbarBubbleView* CreateBubble( + Profile* profile, + SendTabToSelfToolbarButtonView* parent, + const SendTabToSelfEntry& entry, + base::OnceCallback<void(NavigateParams*)> navigate_callback); + + private: + friend class SendTabToSelfToolbarBubbleViewTest; + FRIEND_TEST_ALL_PREFIXES(SendTabToSelfToolbarBubbleViewTest, + ButtonNavigatesToPage); + + SendTabToSelfToolbarBubbleView( + Profile* profile, + SendTabToSelfToolbarButtonView* parent, + const SendTabToSelfEntry& entry, + base::OnceCallback<void(NavigateParams*)> navigate_callback); + + void OpenInNewTab(); + + void Hide(); + + // The button that owns |this|. + SendTabToSelfToolbarButtonView* toolbar_button_; + + base::OnceCallback<void(NavigateParams*)> navigate_callback_; + + Profile* profile_; + + std::string title_; + GURL url_; + std::string device_name_; + std::string guid_; +}; + +} // namespace send_tab_to_self + +#endif // CHROME_BROWSER_UI_VIEWS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_TOOLBAR_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view_unittest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view_unittest.cc new file mode 100644 index 0000000..e3aa063 --- /dev/null +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view_unittest.cc
@@ -0,0 +1,38 @@ +// 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 "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h" + +#include <vector> + +#include "base/callback.h" +#include "base/test/bind.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/ui/views/frame/test_with_browser_view.h" +#include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h" +#include "chrome/test/views/chrome_views_test_base.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" + +namespace send_tab_to_self { + +class SendTabToSelfToolbarBubbleViewTest : public ChromeViewsTestBase {}; + +TEST_F(SendTabToSelfToolbarBubbleViewTest, ButtonNavigatesToPage) { + GURL url("https://www.example.com"); + SendTabToSelfEntry entry("guid", url, "Example", base::Time::Now(), + base::Time::Now(), "Example Device", "sync_guid"); + SendTabToSelfToolbarBubbleView bubble( + nullptr, nullptr, entry, + base::BindLambdaForTesting([&](NavigateParams* params) { + EXPECT_EQ("https://www.example.com", params->url.spec()); + EXPECT_EQ(WindowOpenDisposition::NEW_FOREGROUND_TAB, + params->disposition); + EXPECT_EQ(NavigateParams::SHOW_WINDOW, params->window_action); + })); +} + +} // namespace send_tab_to_self
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.cc index ef2ba9c..4b7a00d 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.cc +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.cc
@@ -7,8 +7,12 @@ #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/send_tab_to_self/receiving_ui_handler_registry.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" #include "components/vector_icons/vector_icons.h" #include "ui/views/controls/button/button_controller.h" @@ -38,16 +42,21 @@ ->SetDelegate(nullptr); } -void SendTabToSelfToolbarButtonView::Show() { +void SendTabToSelfToolbarButtonView::Show(const SendTabToSelfEntry& entry) { + entry_ = &entry; SetVisible(true); } -void SendTabToSelfToolbarButtonView::Hide() { - SetVisible(false); +void SendTabToSelfToolbarButtonView::ButtonPressed() { + SendTabToSelfToolbarBubbleView::CreateBubble( + browser_->profile(), this, *entry_, base::BindOnce(&Navigate)); } -void SendTabToSelfToolbarButtonView::ButtonPressed() { - NOTIMPLEMENTED(); +void SendTabToSelfToolbarButtonView::DismissEntry(std::string& guid) { + send_tab_to_self::ReceivingUiHandlerRegistry::GetInstance() + ->GetToolbarButtonControllerForProfile(browser_->profile()) + ->DismissEntries(std::vector<std::string>({guid})); + SetVisible(false); } } // namespace send_tab_to_self
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h index 16b2756..b50bebf 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_button_view.h
@@ -7,6 +7,7 @@ #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_toolbar_button_controller_delegate.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" +#include "components/send_tab_to_self/send_tab_to_self_entry.h" #include "ui/base/metadata/metadata_header_macros.h" class Browser; @@ -29,13 +30,16 @@ ~SendTabToSelfToolbarButtonView() override; // SendTabToSelfToolbarButtonControllerDelegate implementation. - void Show() override; - void Hide() override; + void Show(const SendTabToSelfEntry& entry) override; + + void DismissEntry(std::string& guid); private: void ButtonPressed(); const Browser* const browser_; + + const SendTabToSelfEntry* entry_; }; } // namespace send_tab_to_self
diff --git a/chrome/browser/ui/views/user_education/README.md b/chrome/browser/ui/views/user_education/README.md new file mode 100644 index 0000000..a7ae142 --- /dev/null +++ b/chrome/browser/ui/views/user_education/README.md
@@ -0,0 +1,2 @@ +Views-specific user education code. See +[//chrome/browser/ui/user_education](../../user_education) for docs.
diff --git a/chrome/browser/ui/views/web_apps/web_app_hover_button.cc b/chrome/browser/ui/views/web_apps/web_app_hover_button.cc index c0024baf..0ced78c 100644 --- a/chrome/browser/ui/views/web_apps/web_app_hover_button.cc +++ b/chrome/browser/ui/views/web_apps/web_app_hover_button.cc
@@ -10,12 +10,9 @@ #include "base/bind.h" #include "base/memory/weak_ptr.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/web_apps/web_app_info_image_source.h" -#include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_id.h" #include "chrome/browser/web_applications/components/web_application_info.h" @@ -25,6 +22,7 @@ #include "components/url_formatter/elide_url.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/image_model.h" #include "ui/events/event.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/button.h" @@ -35,17 +33,16 @@ WebAppHoverButton::WebAppHoverButton(views::Button::PressedCallback callback, const web_app::AppId& app_id, web_app::WebAppProvider* provider, - const std::string& display_name, + const std::u16string& display_name, const GURL& url) : HoverButton(std::move(callback), std::make_unique<NonAccessibleImageView>(), - base::UTF8ToUTF16(base::StringPiece(display_name)), + display_name, l10n_util::GetStringFUTF16( IDS_PROTOCOL_HANDLER_INTENT_PICKER_APP_ORIGIN_LABEL, - web_app::AppBrowserController::FormatUrlOrigin( + url_formatter::FormatUrlForSecurityDisplay( url, - url_formatter::kFormatUrlOmitHTTP | - url_formatter::kFormatUrlOmitHTTPS)), + url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)), /*secondary_view=*/nullptr, /*resize_row_for_secondary_view=*/false, /*secondary_view_can_process_events=*/false), @@ -63,7 +60,16 @@ Layout(); } -inline WebAppHoverButton::~WebAppHoverButton() = default; +WebAppHoverButton::WebAppHoverButton(views::Button::PressedCallback callback, + const gfx::ImageSkia& icon, + const std::u16string& display_name) + : HoverButton(std::move(callback), + ui::ImageModel::FromImageSkia(icon), + display_name) { + Layout(); +} + +WebAppHoverButton::~WebAppHoverButton() = default; void WebAppHoverButton::MarkAsUnselected(const ui::Event* event) { ink_drop()->AnimateToState(views::InkDropState::HIDDEN,
diff --git a/chrome/browser/ui/views/web_apps/web_app_hover_button.h b/chrome/browser/ui/views/web_apps/web_app_hover_button.h index f229d9e..649d6f5 100644 --- a/chrome/browser/ui/views/web_apps/web_app_hover_button.h +++ b/chrome/browser/ui/views/web_apps/web_app_hover_button.h
@@ -13,6 +13,7 @@ #include "chrome/browser/web_applications/components/web_app_id.h" #include "chrome/browser/web_applications/components/web_application_info.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/button.h" #include "url/gurl.h" @@ -39,8 +40,11 @@ WebAppHoverButton(views::Button::PressedCallback callback, const web_app::AppId& app_id, web_app::WebAppProvider* provider, - const std::string& display_name, + const std::u16string& display_name, const GURL& url); + WebAppHoverButton(views::Button::PressedCallback callback, + const gfx::ImageSkia& icon, + const std::u16string& display_name); WebAppHoverButton(const WebAppHoverButton&) = delete; WebAppHoverButton& operator=(const WebAppHoverButton&) = delete; ~WebAppHoverButton() override;
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 d9c8f77..25a71cb 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
@@ -10,7 +10,9 @@ #include "base/callback_forward.h" #include "base/check_op.h" +#include "base/strings/string_piece.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_keep_alive_types.h" #include "chrome/browser/profiles/scoped_profile_keep_alive.h" @@ -154,7 +156,8 @@ web_app::AppRegistrar& registrar = provider->registrar(); auto app_button = std::make_unique<WebAppHoverButton>( views::Button::PressedCallback(), app_id_, provider, - registrar.GetAppShortName(app_id_), registrar.GetAppStartUrl(app_id_)); + base::UTF8ToUTF16(registrar.GetAppShortName(app_id_)), + registrar.GetAppStartUrl(app_id_)); app_button->set_tag(0); app_button->SetTooltipAndAccessibleName(); scrollable_view->AddChildViewAt(std::move(app_button), 0);
diff --git a/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.cc b/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.cc new file mode 100644 index 0000000..5e15810 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.cc
@@ -0,0 +1,45 @@ +// 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/views/web_apps/web_app_url_handler_hover_button.h" + +#include <string> +#include <utility> + +#include "chrome/browser/ui/views/web_apps/web_app_hover_button.h" +#include "chrome/browser/web_applications/components/url_handler_launch_params.h" +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/controls/button/button.h" +#include "url/gurl.h" + +WebAppUrlHandlerHoverButton::WebAppUrlHandlerHoverButton( + views::Button::PressedCallback callback, + const web_app::UrlHandlerLaunchParams& url_handler_launch_params, + web_app::WebAppProvider* provider, + const std::u16string& display_name, + const GURL& app_start_url) + : WebAppHoverButton(std::move(callback), + url_handler_launch_params.app_id, + provider, + display_name, + app_start_url), + url_handler_launch_params_(url_handler_launch_params), + is_app_(true) {} + +WebAppUrlHandlerHoverButton::WebAppUrlHandlerHoverButton( + views::Button::PressedCallback callback) + : WebAppHoverButton( + std::move(callback), + *(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_PRODUCT_LOGO_32)), + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)), + is_app_(false) {} + +WebAppUrlHandlerHoverButton::~WebAppUrlHandlerHoverButton() = default;
diff --git a/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.h b/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.h new file mode 100644 index 0000000..1903be38 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.h
@@ -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. + +#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_HOVER_BUTTON_H_ +#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_HOVER_BUTTON_H_ + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/views/web_apps/web_app_hover_button.h" +#include "chrome/browser/web_applications/components/url_handler_launch_params.h" +#include "ui/views/controls/button/button.h" + +class GURL; + +namespace web_app { +class WebAppProvider; +} + +// WebAppUrlHandlerHoverButton is a hoverable button with a primary left-hand +// icon, a title and a subtitle. +class WebAppUrlHandlerHoverButton : public WebAppHoverButton { + public: + // Creates a hoverable button with the given elements for an app, like so: + // + // +-------------------------------------------------------------------+ + // | | title | + // | icon | | + // | | subtitle | + // +-------------------------------------------------------------------+ + // + WebAppUrlHandlerHoverButton( + views::Button::PressedCallback callback, + const web_app::UrlHandlerLaunchParams& url_handler_launch_params, + web_app::WebAppProvider* provider, + const std::u16string& display_name, + const GURL& app_start_url); + + // Creates a hoverable button for the browser option, like so: + // + // +-------------------------------------------------------------------+ + // | | | + // | icon | title | + // | | | + // +-------------------------------------------------------------------+ + // + explicit WebAppUrlHandlerHoverButton(views::Button::PressedCallback callback); + WebAppUrlHandlerHoverButton(const WebAppUrlHandlerHoverButton&) = delete; + WebAppUrlHandlerHoverButton& operator=(const WebAppUrlHandlerHoverButton&) = + delete; + ~WebAppUrlHandlerHoverButton() override; + + const web_app::UrlHandlerLaunchParams& url_handler_launch_params() const { + return url_handler_launch_params_; + } + + bool is_app() const { return is_app_; } + + private: + const web_app::UrlHandlerLaunchParams url_handler_launch_params_; + // True if the current WebAppUrlHandlerHoverButton is for an app, false if + // it's for the browser. + const bool is_app_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_HOVER_BUTTON_H_
diff --git a/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_browsertest.cc new file mode 100644 index 0000000..9b6e12d8 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_browsertest.cc
@@ -0,0 +1,237 @@ +// 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 <string> +#include <utility> +#include <vector> + +#include "base/callback_helpers.h" +#include "base/files/file_path.h" +#include "base/test/bind.h" +#include "base/test/mock_callback.h" +#include "base/time/time.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.h" +#include "chrome/browser/web_applications/components/os_integration_manager.h" +#include "chrome/browser/web_applications/components/url_handler_launch_params.h" +#include "chrome/browser/web_applications/components/url_handler_manager.h" +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/components/web_application_info.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "content/public/test/browser_test.h" +#include "extensions/browser/extension_dialog_auto_confirm.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/window/dialog_delegate.h" +#include "url/gurl.h" + +namespace { + +const char16_t kAppName[] = u"Test App"; +const char kStartUrl[] = "https://test.com"; +const char kViewClassName[] = "WebAppUrlHandlerIntentPickerView"; + +std::vector<web_app::UrlHandlerLaunchParams> CreateUrlHandlerLaunchParams( + const base::FilePath& profile_path, + const web_app::AppId& app_id) { + std::vector<web_app::UrlHandlerLaunchParams> url_handler_matches; + url_handler_matches.emplace_back(profile_path, app_id, GURL(kStartUrl), + web_app::UrlHandlerSavedChoice::kNone, + base::Time::Now()); + return url_handler_matches; +} + +web_app::AppId InstallTestWebApp(Profile* profile) { + auto app_info = std::make_unique<WebApplicationInfo>(); + app_info->start_url = GURL(kStartUrl); + app_info->title = kAppName; + app_info->open_as_window = true; + return web_app::test::InstallWebApp(profile, std::move(app_info)); +} + +views::DialogDelegate* DialogDelegateFor(views::Widget* widget) { + auto* delegate = widget->widget_delegate()->AsDialogDelegate(); + return delegate; +} + +void AutoCloseDialog(views::Widget* widget) { + // Call CancelDialog to close the dialog, but the actual behavior will be + // determined by the ScopedTestDialogAutoConfirm configs. + views::test::CancelDialog(widget); +} + +} // namespace + +class WebAppUrlHandlerIntentPickerDialogInProcessBrowserTest + : public InProcessBrowserTest {}; + +IN_PROC_BROWSER_TEST_F(WebAppUrlHandlerIntentPickerDialogInProcessBrowserTest, + ShowWebAppUrlHandlerIntentPickerDialog) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kViewClassName); + web_app::AppId test_app_id = InstallTestWebApp(browser()->profile()); + + base::MockCallback<chrome::WebAppUrlHandlerAcceptanceCallback> + show_dialog_callback; + absl::optional<web_app::UrlHandlerLaunchParams> result_launch_params; + bool dialog_accepted; + ON_CALL(show_dialog_callback, Run) + .WillByDefault([&](bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> data) { + dialog_accepted = accepted; + result_launch_params = data; + }); + EXPECT_CALL(show_dialog_callback, Run); + + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, KeepAliveRestartOption::DISABLED); + WebAppUrlHandlerIntentPickerView::Show( + CreateUrlHandlerLaunchParams(browser()->profile()->GetPath(), + test_app_id), + std::move(keep_alive), show_dialog_callback.Get()); + + waiter.WaitIfNeededAndGet()->CloseWithReason( + views::Widget::ClosedReason::kEscKeyPressed); + EXPECT_FALSE(dialog_accepted); + EXPECT_FALSE(result_launch_params.has_value()); +} + +IN_PROC_BROWSER_TEST_F(WebAppUrlHandlerIntentPickerDialogInProcessBrowserTest, + OpenIsDisabledByDefault) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kViewClassName); + web_app::AppId test_app_id = InstallTestWebApp(browser()->profile()); + + base::MockCallback<chrome::WebAppUrlHandlerAcceptanceCallback> + show_dialog_callback; + absl::optional<web_app::UrlHandlerLaunchParams> result_launch_params; + bool dialog_accepted; + ON_CALL(show_dialog_callback, Run) + .WillByDefault([&](bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> data) { + dialog_accepted = accepted; + result_launch_params = data; + }); + EXPECT_CALL(show_dialog_callback, Run); + + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::CANCEL); + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, KeepAliveRestartOption::DISABLED); + WebAppUrlHandlerIntentPickerView::Show( + CreateUrlHandlerLaunchParams(browser()->profile()->GetPath(), + test_app_id), + std::move(keep_alive), show_dialog_callback.Get()); + + auto* widget = waiter.WaitIfNeededAndGet(); + auto* dialog_delegate = DialogDelegateFor(widget); + // Verify "Open" button is disabled by default. + EXPECT_FALSE(dialog_delegate->GetOkButton()->GetEnabled()); + AutoCloseDialog(widget); +} + +IN_PROC_BROWSER_TEST_F(WebAppUrlHandlerIntentPickerDialogInProcessBrowserTest, + SelectBrowser) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kViewClassName); + web_app::AppId test_app_id = InstallTestWebApp(browser()->profile()); + + base::MockCallback<chrome::WebAppUrlHandlerAcceptanceCallback> + show_dialog_callback; + absl::optional<web_app::UrlHandlerLaunchParams> result_launch_params; + bool dialog_accepted; + ON_CALL(show_dialog_callback, Run) + .WillByDefault([&](bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> data) { + dialog_accepted = accepted; + result_launch_params = data; + }); + EXPECT_CALL(show_dialog_callback, Run); + + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 0); + auto launch_params_list = CreateUrlHandlerLaunchParams( + browser()->profile()->GetPath(), test_app_id); + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, KeepAliveRestartOption::DISABLED); + WebAppUrlHandlerIntentPickerView::Show( + launch_params_list, std::move(keep_alive), show_dialog_callback.Get()); + + AutoCloseDialog(waiter.WaitIfNeededAndGet()); + EXPECT_TRUE(dialog_accepted); + EXPECT_FALSE(result_launch_params.has_value()); +} + +IN_PROC_BROWSER_TEST_F(WebAppUrlHandlerIntentPickerDialogInProcessBrowserTest, + SelectApp) { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kViewClassName); + web_app::AppId test_app_id = InstallTestWebApp(browser()->profile()); + + base::MockCallback<chrome::WebAppUrlHandlerAcceptanceCallback> + show_dialog_callback; + absl::optional<web_app::UrlHandlerLaunchParams> result_launch_params; + bool dialog_accepted; + ON_CALL(show_dialog_callback, Run) + .WillByDefault([&](bool accepted, + absl::optional<web_app::UrlHandlerLaunchParams> data) { + dialog_accepted = accepted; + result_launch_params = data; + }); + EXPECT_CALL(show_dialog_callback, Run); + + extensions::ScopedTestDialogAutoConfirm auto_confirm( + extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION, 1); + auto launch_params_list = CreateUrlHandlerLaunchParams( + browser()->profile()->GetPath(), test_app_id); + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, KeepAliveRestartOption::DISABLED); + WebAppUrlHandlerIntentPickerView::Show( + launch_params_list, std::move(keep_alive), show_dialog_callback.Get()); + + AutoCloseDialog(waiter.WaitIfNeededAndGet()); + // Select the second choice - the app. + EXPECT_TRUE(dialog_accepted); + EXPECT_EQ(result_launch_params, launch_params_list[0]); +} + +class WebAppUrlHandlerIntentPickerDialogInteractiveBrowserTest + : public DialogBrowserTest { + public: + // DialogBrowserTest: + void ShowUi(const std::string& name) override { + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + kViewClassName); + + web_app::AppId test_app_id = InstallTestWebApp(browser()->profile()); + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, + KeepAliveRestartOption::DISABLED); + WebAppUrlHandlerIntentPickerView::Show( + CreateUrlHandlerLaunchParams(browser()->profile()->GetPath(), + test_app_id), + std::move(keep_alive), base::DoNothing()); + waiter.WaitIfNeededAndGet()->CloseWithReason( + views::Widget::ClosedReason::kEscKeyPressed); + } +}; + +IN_PROC_BROWSER_TEST_F(WebAppUrlHandlerIntentPickerDialogInteractiveBrowserTest, + InvokeUi_CloseDialog) { + ShowAndVerifyUi(); +}
diff --git a/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.cc b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.cc new file mode 100644 index 0000000..f729c0c --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.cc
@@ -0,0 +1,354 @@ +// 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/views/web_apps/web_app_url_handler_intent_picker_dialog_view.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/check.h" +#include "base/location.h" +#include "base/strings/string_piece_forward.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/web_apps/web_app_url_handler_hover_button.h" +#include "chrome/browser/web_applications/components/app_registrar.h" +#include "chrome/browser/web_applications/components/url_handler_launch_params.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/grit/generated_resources.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "extensions/browser/extension_dialog_auto_confirm.h" +#include "third_party/abseil-cpp/absl/types/optional.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/base/ui_base_types.h" +#include "ui/events/event.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/size.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/checkbox.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" + +namespace { + +// Maximum numbers of web apps we want to show at a time in the dialog. +// The height of the scroll in the dialog depends on how many app +// candidates we got and how many we want to show. If there is more than +// |KMaxAppResults| app candidates, we will show 3.5 apps to let the user +// know there are more than |kMaxAppResults| apps accessible by scrolling +// the list. +constexpr size_t kMaxAppResults = 3; +// This dialog follows the design that +// chrome/browser/ui/views/intent_picker_bubble_view.cc created and the +// main component sizes were also mostly copied over to share the +// same layout. +// Main components sizes +constexpr int kIntentPickerCheckBoxColumnWidth = 288; +constexpr int kMaxIntentPickerWidth = 320; +constexpr int kRowHeight = 32; +constexpr int kTitlePadding = 16; +constexpr gfx::Insets kSeparatorPadding(0, 0, 16, 0); +constexpr SkColor kSeparatorColor = SkColorSetARGB(0x1F, 0x0, 0x0, 0x0); + +std::unique_ptr<views::Separator> CreateHorizontalSeparator() { + auto separator = std::make_unique<views::Separator>(); + separator->SetColor(kSeparatorColor); + separator->SetBorder(views::CreateEmptyBorder(kSeparatorPadding)); + return separator; +} + +} // namespace + +void WebAppUrlHandlerIntentPickerView::Show( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + std::unique_ptr<ScopedKeepAlive> keep_alive, + chrome::WebAppUrlHandlerAcceptanceCallback dialog_close_callback) { + auto view = std::make_unique<WebAppUrlHandlerIntentPickerView>( + std::move(launch_params_list), std::move(keep_alive), + std::move(dialog_close_callback)); + + views::DialogDelegate::CreateDialogWidget(std::move(view), + /*context=*/nullptr, + /*parent=*/nullptr) + ->Show(); +} + +WebAppUrlHandlerIntentPickerView::WebAppUrlHandlerIntentPickerView( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + std::unique_ptr<ScopedKeepAlive> keep_alive, + chrome::WebAppUrlHandlerAcceptanceCallback dialog_close_callback) + : launch_params_list_(std::move(launch_params_list)), + close_callback_(std::move(dialog_close_callback)), + // Pass the ScopedKeepAlive into here ensures the process is alive until + // the dialog is closed, and initiates the shutdown at closure if there + // is nothing else keeping the browser alive. + keep_alive_(std::move(keep_alive)) { + SetDefaultButton(ui::DIALOG_BUTTON_OK); + // Disable the open button by default and enable it when the user has + // selected an option. + SetButtonEnabled(ui::DIALOG_BUTTON_OK, false); + SetModalType(ui::MODAL_TYPE_NONE); + std::u16string title = + l10n_util::GetStringUTF16(IDS_URL_HANDLER_INTENT_PICKER_TITLE); + SetTitle(title); + SetShowCloseButton(true); + + SetButtonLabel( + ui::DIALOG_BUTTON_OK, + l10n_util::GetStringUTF16(IDS_URL_HANDLER_INTENT_PICKER_OK_BUTTON_TEXT)); + SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, + l10n_util::GetStringUTF16( + IDS_URL_HANDLER_INTENT_PICKER_CANCEL_BUTTON_TEXT)); + + SetAcceptCallback(base::BindOnce( + &WebAppUrlHandlerIntentPickerView::OnAccepted, base::Unretained(this))); + + SetCancelCallback(base::BindOnce( + &WebAppUrlHandlerIntentPickerView::OnCanceled, base::Unretained(this))); + + SetCloseCallback(base::BindOnce(&WebAppUrlHandlerIntentPickerView::OnClosed, + base::Unretained(this))); + Initialize(); +} + +WebAppUrlHandlerIntentPickerView::~WebAppUrlHandlerIntentPickerView() = default; + +gfx::Size WebAppUrlHandlerIntentPickerView::CalculatePreferredSize() const { + return gfx::Size(kMaxIntentPickerWidth, + GetHeightForWidth(kMaxIntentPickerWidth)); +} + +absl::optional<web_app::UrlHandlerLaunchParams> +WebAppUrlHandlerIntentPickerView::GetSelectedLaunchParams() const { + // User didn't make a choice, no launch params. + if (!HasUserSelectedApp()) + return absl::nullopt; + + DCHECK(IsSelectedAppValid()); + + if (hover_buttons_[selected_app_tag_.value()]->is_app()) { + return hover_buttons_[selected_app_tag_.value()] + ->url_handler_launch_params(); + } + + // User has selected the browser, no launch params. + return absl::nullopt; +} + +void WebAppUrlHandlerIntentPickerView::SetSelectedAppIndex( + size_t index, + const ui::Event& event) { + DCHECK_GE(index, 0u); + DCHECK_LT(index, hover_buttons_.size()); + if (!HasUserSelectedApp()) { + // User made a choice for the first time, enable the open button. + SetButtonEnabled(ui::DIALOG_BUTTON_OK, true); + } else { + // Unselect the previous user choice. + hover_buttons_[selected_app_tag_.value()]->MarkAsUnselected(nullptr); + } + selected_app_tag_ = index; + hover_buttons_[selected_app_tag_.value()]->MarkAsSelected(&event); + views::View::RequestFocus(); +} + +void WebAppUrlHandlerIntentPickerView::OnAccepted() { + RunCloseCallback(/*accepted=*/true); +} + +void WebAppUrlHandlerIntentPickerView::OnCanceled() { + RunCloseCallback(/*accepted=*/false); +} + +void WebAppUrlHandlerIntentPickerView::OnClosed() { + OnCanceled(); +} + +void WebAppUrlHandlerIntentPickerView::Initialize() { + views::GridLayout* layout = + SetLayoutManager(std::make_unique<views::GridLayout>()); + + // Creates a view to hold the views for each app. + auto scrollable_view = std::make_unique<views::View>(); + scrollable_view->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical)); + + web_app::WebAppProvider* provider; + // Reserve size+1 for the browser entry. + hover_buttons_.reserve(launch_params_list_.size() + 1); + // Create a WebAppUrlHandlerHoverButton to open the link in browser and + // list it as the first choice. + auto app_button = + std::make_unique<WebAppUrlHandlerHoverButton>(base::BindRepeating( + &WebAppUrlHandlerIntentPickerView::SetSelectedAppIndex, + base::Unretained(this), 0)); + app_button->set_tag(0); + hover_buttons_.push_back(app_button.get()); + scrollable_view->AddChildViewAt(std::move(app_button), 0); + + for (const auto& launch_params : launch_params_list_) { + Profile* profile = g_browser_process->profile_manager()->GetProfileByPath( + launch_params.profile_path); + provider = web_app::WebAppProvider::Get(profile); + web_app::AppRegistrar& registrar = provider->registrar(); + + const std::u16string& profile_name = + profiles::GetAvatarNameForProfile(launch_params.profile_path); + const std::u16string& app_name = base::UTF8ToUTF16( + base::StringPiece(registrar.GetAppShortName(launch_params.app_id))); + const std::u16string& app_title = + (profile_name == + l10n_util::GetStringUTF16(IDS_SINGLE_PROFILE_DISPLAY_NAME)) + ? app_name + : l10n_util::GetStringFUTF16( + IDS_URL_HANDLER_INTENT_PICKER_APP_TITLE, app_name, + profile_name); + + const size_t button_index = hover_buttons_.size(); + // TODO(crbug.com/1072058): Make sure the UI is reasonable when + // |app_title| is long. + auto app_button = std::make_unique<WebAppUrlHandlerHoverButton>( + base::BindRepeating( + &WebAppUrlHandlerIntentPickerView::SetSelectedAppIndex, + base::Unretained(this), button_index), + launch_params, provider, app_title, + registrar.GetAppStartUrl(launch_params.app_id)); + app_button->set_tag(button_index); + hover_buttons_.push_back(app_button.get()); + scrollable_view->AddChildViewAt(std::move(app_button), button_index); + } + + auto scroll_view = std::make_unique<views::ScrollView>(); + scroll_view->SetBackgroundThemeColorId( + ui::NativeTheme::kColorId_BubbleBackground); + scroll_view->SetContents(std::move(scrollable_view)); + // This part gives the scroll a fixed width and height. The height depends on + // how many app candidates we got and how many we actually want to show. + // The added 0.5 on the else block allow us to let the user know there are + // more than |kMaxAppResults| apps accessible by scrolling the list. + scroll_view->ClipHeightTo(kRowHeight, (kMaxAppResults + 0.5) * kRowHeight); + + constexpr int kColumnSetId = 0; + views::ColumnSet* cs = layout->AddColumnSet(kColumnSetId); + cs->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, + views::GridLayout::kFixedSize, + views::GridLayout::ColumnSize::kFixed, kMaxIntentPickerWidth, + 0); + + layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnSetId, + views::GridLayout::kFixedSize, kTitlePadding); + scroll_view_ = layout->AddView(std::move(scroll_view)); + layout->StartRow(views::GridLayout::kFixedSize, kColumnSetId, 0); + + // The checkbox allows the user to opt-in to relaxed security + // (i.e. skipping future prompts) for this url. + layout->AddView(CreateHorizontalSeparator()); + // This second ColumnSet has a padding column in order to manipulate the + // Checkbox positioning freely. + constexpr int kColumnSetIdPadded = 2; + views::ColumnSet* cs_padded = layout->AddColumnSet(kColumnSetIdPadded); + cs_padded->AddPaddingColumn(views::GridLayout::kFixedSize, kTitlePadding); + cs_padded->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, + views::GridLayout::kFixedSize, + views::GridLayout::ColumnSize::kFixed, + kIntentPickerCheckBoxColumnWidth, 0); + layout->StartRowWithPadding(views::GridLayout::kFixedSize, kColumnSetIdPadded, + views::GridLayout::kFixedSize, 0); + + if (enable_remember_checkbox_) { + remember_selection_checkbox_ = layout->AddView( + std::make_unique<views::Checkbox>(l10n_util::GetStringUTF16( + IDS_URL_HANDLER_INTENT_PICKER_REMEMBER_SELECTION))); + layout->AddPaddingRow(views::GridLayout::kFixedSize, kRowHeight); + } +} + +void WebAppUrlHandlerIntentPickerView::RunCloseCallback(bool accepted) { + if (!close_callback_) + return; + + absl::optional<web_app::UrlHandlerLaunchParams> launch_params; + bool accepted_override = false; + switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) { + case extensions::ScopedTestDialogAutoConfirm::NONE: + accepted_override = accepted; + launch_params = GetSelectedLaunchParams(); + break; + case extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION: + accepted_override = true; + selected_app_tag_ = + extensions::ScopedTestDialogAutoConfirm::GetOptionSelected(); + launch_params = GetSelectedLaunchParams(); + break; + case extensions::ScopedTestDialogAutoConfirm::ACCEPT: + accepted_override = true; + launch_params = GetSelectedLaunchParams(); + break; + case extensions::ScopedTestDialogAutoConfirm::CANCEL: + accepted_override = false; + launch_params = absl::nullopt; + break; + } + + if (accepted_override && enable_remember_checkbox_ && + remember_selection_checkbox_->GetChecked()) { + // TODO(crbug.com/1072058): Save choice if the user has checked the + // "Remember my choice" box. + } + + std::move(close_callback_).Run(accepted_override, std::move(launch_params)); +} + +bool WebAppUrlHandlerIntentPickerView::IsSelectedAppValid() const { + return selected_app_tag_.has_value() && selected_app_tag_.value() >= 0 && + selected_app_tag_.value() < static_cast<int>(hover_buttons_.size()); +} + +bool WebAppUrlHandlerIntentPickerView::HasUserSelectedApp() const { + return selected_app_tag_.has_value(); +} + +BEGIN_METADATA(WebAppUrlHandlerIntentPickerView, views::DialogDelegateView) +END_METADATA + +namespace chrome { + +// static +void ShowWebAppUrlHandlerIntentPickerDialog( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + WebAppUrlHandlerAcceptanceCallback dialog_close_callback) { + DCHECK(dialog_close_callback); + + // TODO(crbug.com/1200951): Update the following accordingly for multi- + // profile URL handler launch support. + auto* provider = web_app::WebAppProvider::Get( + g_browser_process->profile_manager()->GetProfileByPath( + launch_params_list.front().profile_path)); + DCHECK(provider); + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_INTENT_PICKER, KeepAliveRestartOption::DISABLED); + provider->on_registry_ready().Post( + FROM_HERE, + base::BindOnce(&WebAppUrlHandlerIntentPickerView::Show, + std::move(launch_params_list), std::move(keep_alive), + std::move(dialog_close_callback))); +} + +} // namespace chrome
diff --git a/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.h b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.h new file mode 100644 index 0000000..e5a6c0a --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_view.h
@@ -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. + +#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_INTENT_PICKER_DIALOG_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_INTENT_PICKER_DIALOG_VIEW_H_ + +#include <memory> +#include <vector> + +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/web_applications/components/url_handler_launch_params.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/views/window/dialog_delegate.h" + +class ScopedKeepAlive; +class WebAppUrlHandlerHoverButton; + +namespace gfx { +class Size; +} + +namespace ui { +class Event; +} + +namespace views { +class Checkbox; +class ScrollView; +} // namespace views + +// The dialog's view, owned by the views framework. +// TODO(crbug.com/1209222): Dialog should be accessible. +class WebAppUrlHandlerIntentPickerView : public views::DialogDelegateView { + public: + METADATA_HEADER(WebAppUrlHandlerIntentPickerView); + + WebAppUrlHandlerIntentPickerView( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + std::unique_ptr<ScopedKeepAlive> keep_alive, + chrome::WebAppUrlHandlerAcceptanceCallback dialog_close_callback); + WebAppUrlHandlerIntentPickerView(const WebAppUrlHandlerIntentPickerView&) = + delete; + WebAppUrlHandlerIntentPickerView& operator=( + const WebAppUrlHandlerIntentPickerView&) = delete; + ~WebAppUrlHandlerIntentPickerView() override; + + static void Show( + std::vector<web_app::UrlHandlerLaunchParams> launch_params_list, + std::unique_ptr<ScopedKeepAlive> keep_alive, + chrome::WebAppUrlHandlerAcceptanceCallback dialog_close_callback); + + private: + void Initialize(); + // views::DialogDelegateView: + gfx::Size CalculatePreferredSize() const override; + + // Return the UrlHandlerLaunchParams for the selected option. Null when the + // browser is selected. + absl::optional<web_app::UrlHandlerLaunchParams> GetSelectedLaunchParams() + const; + + void OnAccepted(); + void OnCanceled(); + // Close callback called by DialogDeletegate. See + // DialogDelegate::SetCloseCallback for when it's called. + void OnClosed(); + + // Unselects the current focused app item on the list and + // refocus on the selected app item based on the index provided. + void SetSelectedAppIndex(size_t index, const ui::Event& event); + + // Runs the close_callback_ provided during Show() if it exists. + void RunCloseCallback(bool accepted); + + // Return if the |selected_app_tag_| is valid. + bool IsSelectedAppValid() const; + // Return if the user has selected an app in the dialog. + bool HasUserSelectedApp() const; + + const std::vector<web_app::UrlHandlerLaunchParams> launch_params_list_; + chrome::WebAppUrlHandlerAcceptanceCallback close_callback_; + std::unique_ptr<ScopedKeepAlive> keep_alive_; + + std::vector<WebAppUrlHandlerHoverButton*> hover_buttons_; + // Allow the checkbox to be enabled or disabled. + // TODO(crbug.com/1072058): Remove when settings are implemented. + const bool enable_remember_checkbox_ = true; + views::Checkbox* remember_selection_checkbox_ = nullptr; + views::ScrollView* scroll_view_ = nullptr; + + // No default selection. Not null if selected by user. + absl::optional<int> selected_app_tag_ = absl::nullopt; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_URL_HANDLER_INTENT_PICKER_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc index 0f4363da..2c1be6e 100644 --- a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc +++ b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
@@ -123,14 +123,14 @@ } // This test is flaky on MacOS with ASAN or DBG. https://crbug.com/1173317 +// Also flaky on MacOS in general, see https://crbug.com/1216076 #if defined(OS_MAC) -#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG) #define MAYBE_AnchorLinkClick DISABLED_AnchorLinkClick #else #define MAYBE_AnchorLinkClick AnchorLinkClick -#endif // ADDRESS_SANITIZER || !NDEBUG #endif // OS_MAC -IN_PROC_BROWSER_TEST_P(SystemWebAppLinkCaptureBrowserTest, AnchorLinkClick) { +IN_PROC_BROWSER_TEST_P(SystemWebAppLinkCaptureBrowserTest, + MAYBE_AnchorLinkClick) { WaitForTestSystemAppInstall(); GURL kInitiatingChromeUrl = GURL(chrome::kChromeUIAboutURL); @@ -303,7 +303,13 @@ ->GetLastCommittedURL()); } -IN_PROC_BROWSER_TEST_P(SystemWebAppLinkCaptureBrowserTest, WindowOpen) { +// Flaky on Mac, see https://crbug.com/1216076 +#if defined(OS_MAC) +#define MAYBE_WindowOpen DISABLED_WindowOpen +#else +#define MAYBE_WindowOpen WindowOpen +#endif // OS_MAC +IN_PROC_BROWSER_TEST_P(SystemWebAppLinkCaptureBrowserTest, MAYBE_WindowOpen) { WaitForTestSystemAppInstall(); GURL kInitiatingChromeUrl = GURL(chrome::kChromeUIAboutURL); @@ -350,8 +356,14 @@ } } +// Flaky on Mac, see https://crbug.com/1216076 +#if defined(OS_MAC) +#define MAYBE_WindowOpenFromOtherSWA DISABLED_WindowOpenFromOtherSWA +#else +#define MAYBE_WindowOpenFromOtherSWA WindowOpenFromOtherSWA +#endif // OS_MAC IN_PROC_BROWSER_TEST_P(SystemWebAppLinkCaptureBrowserTest, - WindowOpenFromOtherSWA) { + MAYBE_WindowOpenFromOtherSWA) { WaitForTestSystemAppInstall(); content::WebContents* initiating_web_contents = LaunchApp(kInitiatingAppType);
diff --git a/chrome/browser/ui/web_applications/web_app_uninstall_browsertest.cc b/chrome/browser/ui/web_applications/web_app_uninstall_browsertest.cc index b57609d3..b082a025 100644 --- a/chrome/browser/ui/web_applications/web_app_uninstall_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_uninstall_browsertest.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/web_applications/components/install_finalizer.h" #include "chrome/browser/web_applications/components/web_app_id.h" #include "chrome/browser/web_applications/components/web_app_provider_base.h" +#include "chrome/browser/web_applications/isolation_prefs_utils.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_registrar.h" #include "components/services/app_service/public/mojom/types.mojom.h" @@ -183,4 +184,28 @@ EXPECT_FALSE(provider->registrar().IsInstalled(app_id)); } +IN_PROC_BROWSER_TEST_F(WebAppUninstallBrowserTest, PrefsRemovedAfterUninstall) { + const GURL app_url = GetSecureAppURL(); + const url::Origin origin = url::Origin::Create(app_url); + auto web_app_info = std::make_unique<WebApplicationInfo>(); + web_app_info->start_url = app_url; + web_app_info->scope = app_url.GetWithoutFilename(); + web_app_info->is_storage_isolated = true; + const AppId app_id = InstallWebApp(std::move(web_app_info)); + + { + const std::string* storage_isolation_key = + GetStorageIsolationKey(profile()->GetPrefs(), origin); + EXPECT_EQ(*storage_isolation_key, app_id); + } + + UninstallWebApp(app_id); + + { + const std::string* storage_isolation_key = + GetStorageIsolationKey(profile()->GetPrefs(), origin); + EXPECT_EQ(storage_isolation_key, nullptr); + } +} + } // namespace web_app
diff --git a/chrome/browser/ui/webui/flags/flags_ui_handler.cc b/chrome/browser/ui/webui/flags/flags_ui_handler.cc index b5ae7942..6284942c 100644 --- a/chrome/browser/ui/webui/flags/flags_ui_handler.cc +++ b/chrome/browser/ui/webui/flags/flags_ui_handler.cc
@@ -23,7 +23,7 @@ FlagsUIHandler::FlagsUIHandler() : access_(flags_ui::kGeneralAccessFlagsOnly), - experimental_features_requested_(false), + experimental_features_callback_id_(""), deprecated_features_only_(false) {} FlagsUIHandler::~FlagsUIHandler() {} @@ -57,8 +57,8 @@ flags_storage_.reset(flags_storage); access_ = access; - if (experimental_features_requested_) - HandleRequestExperimentalFeatures(nullptr); + if (!experimental_features_callback_id_.empty()) + SendExperimentalFeatures(); } void FlagsUIHandler::HandleRequestExperimentalFeatures( @@ -66,14 +66,17 @@ AllowJavascript(); const base::Value& callback_id = args->GetList()[0]; - experimental_features_requested_ = true; + experimental_features_callback_id_ = callback_id.GetString(); // Bail out if the handler hasn't been initialized yet. The request will be // handled after the initialization. if (!flags_storage_) { - ResolveJavascriptCallback(callback_id, base::Value()); return; } + SendExperimentalFeatures(); +} + +void FlagsUIHandler::SendExperimentalFeatures() { base::DictionaryValue results; std::unique_ptr<base::ListValue> supported_features(new base::ListValue); @@ -108,7 +111,9 @@ results.SetBoolean(flags_ui::kShowBetaChannelPromotion, false); results.SetBoolean(flags_ui::kShowDevChannelPromotion, false); #endif - ResolveJavascriptCallback(callback_id, results); + ResolveJavascriptCallback(base::Value(experimental_features_callback_id_), + results); + experimental_features_callback_id_.clear(); } void FlagsUIHandler::HandleEnableExperimentalFeatureMessage(
diff --git a/chrome/browser/ui/webui/flags/flags_ui_handler.h b/chrome/browser/ui/webui/flags/flags_ui_handler.h index 743a601..ae061a8d 100644 --- a/chrome/browser/ui/webui/flags/flags_ui_handler.h +++ b/chrome/browser/ui/webui/flags/flags_ui_handler.h
@@ -23,9 +23,12 @@ // Initializes the UI handler with the provided flags storage and flags // access. If there were flags experiments requested from javascript before - // this was called, it calls |HandleRequestExperimentalFeatures| again. + // this was called, it calls |SendExperimentalFeatures|. void Init(flags_ui::FlagsStorage* flags_storage, flags_ui::FlagAccess access); + // Sends experimental features lists to the UI. + void SendExperimentalFeatures(); + // Configures the handler to return either all features or deprecated // features only. void set_deprecated_features_only(bool deprecatedFeaturesOnly) { @@ -53,7 +56,7 @@ private: std::unique_ptr<flags_ui::FlagsStorage> flags_storage_; flags_ui::FlagAccess access_; - bool experimental_features_requested_; + std::string experimental_features_callback_id_; bool deprecated_features_only_; DISALLOW_COPY_AND_ASSIGN(FlagsUIHandler);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc index 40c902f..d00e3ecf 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos.cc
@@ -31,7 +31,6 @@ #include "content/public/browser/web_ui.h" #if BUILDFLAG(IS_CHROMEOS_ASH) -#include "ash/constants/ash_features.h" #include "chrome/browser/ash/account_manager/account_manager_util.h" #include "chrome/browser/chromeos/printing/cups_printers_manager.h" #include "chrome/browser/chromeos/printing/cups_printers_manager_factory.h" @@ -143,8 +142,6 @@ PrintPreviewHandlerChromeOS::~PrintPreviewHandlerChromeOS() { #if BUILDFLAG(IS_CHROMEOS_ASH) - if (!base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)) - return; Profile* profile = Profile::FromWebUI(web_ui()); auto* cups_manager = chromeos::CupsPrintersManagerFactory::GetForBrowserContext(profile); @@ -180,10 +177,6 @@ base::BindRepeating( &PrintPreviewHandlerChromeOS::HandleRequestPrinterStatusUpdate, base::Unretained(this))); -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (!base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)) - return; -#endif web_ui()->RegisterMessageCallback( "choosePrintServers", base::BindRepeating( @@ -198,8 +191,6 @@ void PrintPreviewHandlerChromeOS::OnJavascriptAllowed() { #if BUILDFLAG(IS_CHROMEOS_ASH) - if (!base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)) - return; Profile* profile = Profile::FromWebUI(web_ui()); print_servers_manager_ = chromeos::CupsPrintersManagerFactory::GetForBrowserContext(profile) @@ -221,8 +212,6 @@ // this is necessary for refresh or navigation from the chrome://print page. weak_factory_.InvalidateWeakPtrs(); #if BUILDFLAG(IS_CHROMEOS_ASH) - if (!base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)) - return; print_servers_manager_->RemoveObserver(this); #elif BUILDFLAG(IS_CHROMEOS_LACROS) receiver_.reset();
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc index e7e74c7..81bc6638 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_chromeos_unittest.cc
@@ -8,7 +8,6 @@ #include "base/run_loop.h" #include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" #include "base/values.h" #include "chrome/browser/chromeos/printing/cups_printers_manager.h" #include "chrome/browser/chromeos/printing/cups_printers_manager_factory.h" @@ -22,9 +21,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "ash/constants/ash_features.h" -#elif BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chromeos/crosapi/mojom/local_printer.mojom.h" #endif @@ -192,10 +189,6 @@ ~PrintPreviewHandlerChromeOSTest() override = default; void SetUp() override { -#if BUILDFLAG(IS_CHROMEOS_ASH) - scoped_feature_list_.InitWithFeatures( - {chromeos::features::kPrintServerScaling}, {}); -#endif TestingProfile::Builder builder; profile_ = builder.Build(); #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -271,7 +264,6 @@ private: content::BrowserTaskEnvironment task_environment_; - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<TestingProfile> profile_; #if BUILDFLAG(IS_CHROMEOS_ASH) std::unique_ptr<TestPrintServersManager> print_servers_manager_;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index bf8112d..6a8d973 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -412,18 +412,6 @@ "forceEnablePrivetPrinting", profile->GetPrefs()->GetBoolean(prefs::kForceEnablePrivetPrinting)); #endif - -#if BUILDFLAG(IS_CHROMEOS_ASH) - source->AddBoolean( - "showPrinterStatusInDialog", - base::FeatureList::IsEnabled(chromeos::features::kPrinterStatusDialog)); - source->AddBoolean( - "printServerScaling", - base::FeatureList::IsEnabled(chromeos::features::kPrintServerScaling)); -#elif BUILDFLAG(IS_CHROMEOS_LACROS) - source->AddBoolean("showPrinterStatusInDialog", true); - source->AddBoolean("printServerScaling", true); -#endif } void SetupPrintPreviewPlugin(content::WebUIDataSource* source) {
diff --git a/chrome/browser/ui/webui/tab_search/BUILD.gn b/chrome/browser/ui/webui/tab_search/BUILD.gn index 1ec3de6..b7ac263 100644 --- a/chrome/browser/ui/webui/tab_search/BUILD.gn +++ b/chrome/browser/ui/webui/tab_search/BUILD.gn
@@ -6,6 +6,9 @@ mojom("mojo_bindings") { sources = [ "tab_search.mojom" ] - public_deps = [ "//mojo/public/mojom/base" ] + public_deps = [ + "//components/tab_groups/public/mojom:mojo_bindings", + "//mojo/public/mojom/base", + ] webui_module_path = "/" }
diff --git a/chrome/browser/ui/webui/tab_search/tab_search.mojom b/chrome/browser/ui/webui/tab_search/tab_search.mojom index 135f7e9..9b37079 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search.mojom +++ b/chrome/browser/ui/webui/tab_search/tab_search.mojom
@@ -5,11 +5,14 @@ module tab_search.mojom; import "mojo/public/mojom/base/time.mojom"; +import "mojo/public/mojom/base/token.mojom"; +import "components/tab_groups/public/mojom/tab_group_types.mojom"; // Collection of window details associated with a profile. struct ProfileData { array<Window> windows; array<RecentlyClosedTab> recently_closed_tabs; + array<TabGroup> tab_groups; }; // Properties and tabs associated with a window. @@ -31,7 +34,7 @@ int32 tab_id; // The group identifier of the tab. - string? group_id; + mojo_base.mojom.Token? group_id; // Whether the tab is pinned. bool pinned; @@ -80,15 +83,15 @@ string last_active_elapsed_text; }; -// Collection of tab groups. -struct TabGroups { - map<string, TabGroup> groups; -}; - // Information about a tab group. struct TabGroup { - string color; - string text_color; + // The unique identifier of the tab group. + mojo_base.mojom.Token id; + + // The color of the tab group. + tab_groups.mojom.Color color; + + // The title of the tab group. string title; }; @@ -112,9 +115,6 @@ // Get window and tab data for the current profile. GetProfileData() => (ProfileData profile_data); - // Get tab groups for the current profile. - GetTabGroups() => (TabGroups tab_groups); - // Switch to a specific tab. SwitchToTab(SwitchToTabInfo switch_to_tab_info);
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc index 84ee293..235956a 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -17,6 +17,7 @@ #include "base/timer/timer.h" #include "base/trace_event/trace_event.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/extensions/api/tab_groups/tab_groups_util.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/favicon/favicon_utils.h" #include "chrome/browser/profiles/profile.h" @@ -136,12 +137,6 @@ return absl::nullopt; } -void TabSearchPageHandler::GetTabGroups(GetTabGroupsCallback callback) { - // TODO(crbug.com/1096120): Implement this when we can get theme color from - // browser - NOTIMPLEMENTED(); -} - void TabSearchPageHandler::SwitchToTab( tab_search::mojom::SwitchToTabInfoPtr switch_to_tab_info) { absl::optional<TabDetails> optional_details = @@ -188,6 +183,7 @@ if (!ShouldTrackBrowser(browser)) continue; TabStripModel* tab_strip_model = browser->tab_strip_model(); + auto window = tab_search::mojom::Window::New(); window->active = (browser == active_browser); window->height = browser->window()->GetContentsSize().height(); @@ -198,6 +194,19 @@ window->tabs.push_back(std::move(tab)); } profile_data->windows.push_back(std::move(window)); + + for (auto tab_group_id : tab_strip_model->group_model()->ListTabGroups()) { + const tab_groups::TabGroupVisualData* tab_group_visual_data = + tab_strip_model->group_model() + ->GetTabGroup(tab_group_id) + ->visual_data(); + + auto tab_group = tab_search::mojom::TabGroup::New(); + tab_group->id = tab_group_id.token(); + tab_group->title = base::UTF16ToUTF8(tab_group_visual_data->title()); + tab_group->color = tab_group_visual_data->color(); + profile_data->tab_groups.push_back(std::move(tab_group)); + } } AddRecentlyClosedTabs(profile_data->recently_closed_tabs, tab_urls); @@ -289,7 +298,7 @@ const absl::optional<tab_groups::TabGroupId> group_id = tab_strip_model->GetTabGroupForTab(index); if (group_id.has_value()) { - tab_data->group_id = group_id.value().ToString(); + tab_data->group_id = group_id.value().token(); } TabRendererData tab_renderer_data = TabRendererData::FromTabInModel(tab_strip_model, index);
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h index adb8578..6114edd8 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.h
@@ -48,7 +48,6 @@ // tab_search::mojom::PageHandler: void CloseTab(int32_t tab_id) override; void GetProfileData(GetProfileDataCallback callback) override; - void GetTabGroups(GetTabGroupsCallback callback) override; void SwitchToTab( tab_search::mojom::SwitchToTabInfoPtr switch_to_tab_info) override; void OpenRecentlyClosedTab(int32_t tab_id) override;
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc index 0308fe16..7f5f343 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -18,6 +18,9 @@ #include "chrome/test/base/testing_profile_manager.h" #include "components/sessions/core/tab_restore_service_impl.h" #include "components/sync_preferences/pref_service_syncable.h" +#include "components/tab_groups/tab_group_color.h" +#include "components/tab_groups/tab_group_id.h" +#include "components/tab_groups/tab_group_visual_data.h" #include "content/public/test/test_web_ui.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/color_utils.h" @@ -289,6 +292,42 @@ handler()->GetProfileData(std::move(callback3)); } +TEST_F(TabSearchPageHandlerTest, GetTabsAndGroups) { + // Add tabs to a browser. + AddTabWithTitle(browser1(), GURL(kTabUrl1), kTabName1); + AddTabWithTitle(browser1(), GURL(kTabUrl2), kTabName2); + + TabStripModel* tab_strip_model = browser1()->tab_strip_model(); + TabGroupModel* tab_group_model = tab_strip_model->group_model(); + + EXPECT_CALL(page_, TabUpdated(_)).Times(1); + EXPECT_CALL(page_, TabsRemoved(_)).Times(1); + // Associate a tab to a given tab group. + tab_groups::TabGroupId group1 = tab_strip_model->AddToNewGroup({0}); + + std::u16string sample_title = u"Sample title"; + const tab_groups::TabGroupColorId sample_color = + tab_groups::TabGroupColorId::kGrey; + tab_groups::TabGroupVisualData visual_data1(sample_title, sample_color); + tab_group_model->GetTabGroup(group1)->SetVisualData(visual_data1); + + // Get Tabs and Tab Group details. + tab_search::mojom::PageHandler::GetProfileDataCallback callback1 = + base::BindLambdaForTesting( + [&](tab_search::mojom::ProfileDataPtr profile_tabs) { + ASSERT_EQ(2u, profile_tabs->windows.size()); + auto* window1 = profile_tabs->windows[0].get(); + ASSERT_TRUE(window1->active); + ASSERT_EQ(2u, window1->tabs.size()); + + ASSERT_EQ(1u, profile_tabs->tab_groups.size()); + auto* tab_group = profile_tabs->tab_groups[0].get(); + ASSERT_EQ(sample_color, tab_group->color); + ASSERT_EQ(base::UTF16ToUTF8(sample_title), tab_group->title); + }); + handler()->GetProfileData(std::move(callback1)); +} + // Ensure that repeated tab model changes do not result in repeated calls to // TabsChanged() and TabsChanged() is only called when the page handler's // timer fires.
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 1dba26ec..b42286f 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -24,6 +24,8 @@ "externally_managed_app_registration_task.h", "file_utils_wrapper.cc", "file_utils_wrapper.h", + "isolation_prefs_utils.cc", + "isolation_prefs_utils.h", "manifest_update_manager.cc", "manifest_update_manager.h", "manifest_update_task.cc", @@ -104,6 +106,7 @@ "//components/webapps/browser", "//content/public/browser", "//services/metrics/public/cpp:ukm_builders", + "//services/preferences/public/cpp", "//skia", "//ui/base/idle", "//ui/events/devices:devices", @@ -263,6 +266,7 @@ sources = [ "daily_metrics_helper_unittest.cc", "externally_managed_app_manager_impl_unittest.cc", + "isolation_prefs_utils_unittest.cc", "manifest_update_task_unittest.cc", "preinstalled_web_app_manager_unittest.cc", "preinstalled_web_app_utils_unittest.cc",
diff --git a/chrome/browser/web_applications/components/url_handler_launch_params.cc b/chrome/browser/web_applications/components/url_handler_launch_params.cc index 2a19c66..d80cee6 100644 --- a/chrome/browser/web_applications/components/url_handler_launch_params.cc +++ b/chrome/browser/web_applications/components/url_handler_launch_params.cc
@@ -8,6 +8,8 @@ namespace web_app { +UrlHandlerLaunchParams::UrlHandlerLaunchParams() = default; + UrlHandlerLaunchParams::UrlHandlerLaunchParams( const base::FilePath& profile_path, const AppId& app_id, @@ -29,4 +31,14 @@ UrlHandlerLaunchParams::~UrlHandlerLaunchParams() = default; +bool operator==(const UrlHandlerLaunchParams& launch_params1, + const UrlHandlerLaunchParams& launch_params2) { + return launch_params1.profile_path == launch_params2.profile_path && + launch_params1.app_id == launch_params2.app_id && + launch_params1.url == launch_params2.url && + launch_params1.saved_choice == launch_params2.saved_choice && + launch_params1.saved_choice_timestamp == + launch_params2.saved_choice_timestamp; +} + } // namespace web_app
diff --git a/chrome/browser/web_applications/components/url_handler_launch_params.h b/chrome/browser/web_applications/components/url_handler_launch_params.h index 1c6e695..8d640e3 100644 --- a/chrome/browser/web_applications/components/url_handler_launch_params.h +++ b/chrome/browser/web_applications/components/url_handler_launch_params.h
@@ -34,6 +34,7 @@ // |saved_choice| can be used to determine if a UI prompt needs to be shown to // the user before launch. struct UrlHandlerLaunchParams { + UrlHandlerLaunchParams(); UrlHandlerLaunchParams(const base::FilePath& profile_path, const AppId& app_id, const GURL& url, @@ -51,6 +52,9 @@ base::Time saved_choice_timestamp; }; +bool operator==(const UrlHandlerLaunchParams& launch_params1, + const UrlHandlerLaunchParams& launch_params2); + } // namespace web_app #endif // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_URL_HANDLER_LAUNCH_PARAMS_H_
diff --git a/chrome/browser/web_applications/components/web_app_prefs_utils.cc b/chrome/browser/web_applications/components/web_app_prefs_utils.cc index ad6fbf4..d373fdc 100644 --- a/chrome/browser/web_applications/components/web_app_prefs_utils.cc +++ b/chrome/browser/web_applications/components/web_app_prefs_utils.cc
@@ -87,6 +87,12 @@ // since the Windows epoch, using util::TimeToValue(). // "IPH_last_ignore_time": "13249617864945500", // }, +// isolation_state is managed by isolation_prefs_utils +// "isolation_state": { +// "<origin>": { +// "storage_isolation_key": "abc123", +// }, +// }, // } // const char kWasExternalAppUninstalledByUser[] =
diff --git a/chrome/browser/web_applications/isolation_prefs_utils.cc b/chrome/browser/web_applications/isolation_prefs_utils.cc new file mode 100644 index 0000000..cb95a7e --- /dev/null +++ b/chrome/browser/web_applications/isolation_prefs_utils.cc
@@ -0,0 +1,82 @@ +// 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/web_applications/isolation_prefs_utils.h" + +#include <memory> + +#include "base/values.h" +#include "chrome/browser/web_applications/components/web_app_prefs_utils.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "services/preferences/public/cpp/dictionary_value_update.h" +#include "services/preferences/public/cpp/scoped_pref_update.h" +#include "url/origin.h" + +namespace web_app { + +// The stored preferences managed by this file look like: +// "web_apps": { +// ... other fields managed by web_app_prefs_utils ... +// +// "isolation_state": { +// "<origin>": { +// "storage_isolation_key": "abc123", +// }, +// }, +// } + +const char kStorageIsolationKey[] = "storage_isolation_key"; + +void IsolationPrefsUtilsRegisterProfilePrefs(PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(::prefs::kWebAppsIsolationState); +} + +void RecordOrRemoveAppIsolationState(PrefService* pref_service, + const WebApp& web_app) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + url::Origin origin = url::Origin::Create(web_app.scope()); + + prefs::ScopedDictionaryPrefUpdate update(pref_service, + prefs::kWebAppsIsolationState); + if (web_app.IsStorageIsolated()) { + std::unique_ptr<prefs::DictionaryValueUpdate> origin_isolation_update; + if (!update->GetDictionaryWithoutPathExpansion(origin.Serialize(), + &origin_isolation_update)) { + origin_isolation_update = update->SetDictionaryWithoutPathExpansion( + origin.Serialize(), std::make_unique<base::DictionaryValue>()); + } + origin_isolation_update->SetString(kStorageIsolationKey, web_app.app_id()); + } else { + update->RemoveWithoutPathExpansion(origin.Serialize(), nullptr); + } +} + +void RemoveAppIsolationState(PrefService* pref_service, + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + prefs::ScopedDictionaryPrefUpdate update(pref_service, + prefs::kWebAppsIsolationState); + update->RemoveWithoutPathExpansion(origin.Serialize(), nullptr); +} + +const std::string* GetStorageIsolationKey(PrefService* pref_service, + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + const base::DictionaryValue* isolation_prefs = + pref_service->GetDictionary(prefs::kWebAppsIsolationState); + if (!isolation_prefs) + return nullptr; + + const base::Value* origin_prefs = + isolation_prefs->FindDictKey(origin.Serialize()); + if (!origin_prefs) + return nullptr; + return origin_prefs->FindStringKey(kStorageIsolationKey); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/isolation_prefs_utils.h b/chrome/browser/web_applications/isolation_prefs_utils.h new file mode 100644 index 0000000..db7ecdf --- /dev/null +++ b/chrome/browser/web_applications/isolation_prefs_utils.h
@@ -0,0 +1,42 @@ +// 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_WEB_APPLICATIONS_ISOLATION_PREFS_UTILS_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATION_PREFS_UTILS_H_ + +#include <string> + +class PrefRegistrySimple; +class PrefService; + +namespace url { +class Origin; +} + +namespace web_app { + +class WebApp; + +extern const char kStorageIsolation[]; + +void IsolationPrefsUtilsRegisterProfilePrefs(PrefRegistrySimple* registry); + +// Updates |web_app|'s entry in the "isolation_state" dictionary to be in sync +// with its current isolation state. +void RecordOrRemoveAppIsolationState(PrefService* pref_service, + const WebApp& web_app); + +// Removes |web_app|'s entry in the "isolation_state" dictionary. Must be called +// when uninstalling an app. +void RemoveAppIsolationState(PrefService* pref_service, + const url::Origin& origin); + +// Returns the storage isolation key to use when loading resources +// from |origin|. +const std::string* GetStorageIsolationKey(PrefService* pref_service, + const url::Origin& origin); + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATION_PREFS_UTILS_H_
diff --git a/chrome/browser/web_applications/isolation_prefs_utils_unittest.cc b/chrome/browser/web_applications/isolation_prefs_utils_unittest.cc new file mode 100644 index 0000000..7fe914b --- /dev/null +++ b/chrome/browser/web_applications/isolation_prefs_utils_unittest.cc
@@ -0,0 +1,106 @@ +// 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/web_applications/isolation_prefs_utils.h" + +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/web_app.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/origin.h" + +namespace web_app { + +namespace { +const AppId app_id = "test_app"; +const std::string scope("https://example.com/pwa"); +} // namespace + +class IsolationPrefsUtilsTest : public testing::Test { + public: + IsolationPrefsUtilsTest() { + IsolationPrefsUtilsRegisterProfilePrefs(prefs_.registry()); + } + + sync_preferences::TestingPrefServiceSyncable* prefs() { return &prefs_; } + + protected: + content::BrowserTaskEnvironment task_environment_; + + private: + sync_preferences::TestingPrefServiceSyncable prefs_; +}; + +TEST_F(IsolationPrefsUtilsTest, TestInstallNonIsolatedApp) { + WebApp app(app_id); + app.SetScope(GURL(scope)); + + RecordOrRemoveAppIsolationState(prefs(), app); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_EQ(storage_isolation_key, nullptr); +} + +TEST_F(IsolationPrefsUtilsTest, TestInstallIsolatedApp) { + WebApp app(app_id); + app.SetScope(GURL(scope)); + app.SetStorageIsolated(true); + + RecordOrRemoveAppIsolationState(prefs(), app); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_NE(storage_isolation_key, nullptr); + EXPECT_EQ(*storage_isolation_key, app_id); +} + +TEST_F(IsolationPrefsUtilsTest, TestUpdateIsolatedApp) { + WebApp app(app_id); + app.SetScope(GURL(scope)); + app.SetStorageIsolated(true); + + { + RecordOrRemoveAppIsolationState(prefs(), app); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_NE(storage_isolation_key, nullptr); + EXPECT_EQ(*storage_isolation_key, app_id); + } + + { + app.SetStorageIsolated(false); + RecordOrRemoveAppIsolationState(prefs(), app); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_EQ(storage_isolation_key, nullptr); + } +} + +TEST_F(IsolationPrefsUtilsTest, TestUninstallIsolatedApp) { + WebApp app(app_id); + app.SetScope(GURL(scope)); + app.SetStorageIsolated(true); + + { + RecordOrRemoveAppIsolationState(prefs(), app); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_NE(storage_isolation_key, nullptr); + EXPECT_EQ(*storage_isolation_key, app_id); + } + + { + RemoveAppIsolationState(prefs(), url::Origin::Create(app.scope())); + + const std::string* storage_isolation_key = + GetStorageIsolationKey(prefs(), url::Origin::Create(app.scope())); + EXPECT_EQ(storage_isolation_key, nullptr); + } +} +} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index 0832123f..1a55816a 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -31,6 +31,7 @@ #include "chrome/browser/web_applications/components/web_app_system_web_app_data.h" #include "chrome/browser/web_applications/components/web_app_utils.h" #include "chrome/browser/web_applications/components/web_application_info.h" +#include "chrome/browser/web_applications/isolation_prefs_utils.h" #include "chrome/browser/web_applications/manifest_update_task.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_icon_manager.h" @@ -480,6 +481,13 @@ webapps::WebappUninstallSource uninstall_source, UninstallWebAppCallback callback, OsHooksResults os_hooks_info) { + WebAppRegistrar* web_app_registrar = registrar().AsWebAppRegistrar(); + DCHECK(web_app_registrar); + const WebApp* web_app = web_app_registrar->GetAppById(app_id); + DCHECK(web_app); + RemoveAppIsolationState(profile_->GetPrefs(), + url::Origin::Create(web_app->scope())); + ScopedRegistryUpdate update(registry_controller().AsWebAppSyncBridge()); update->DeleteApp(app_id); @@ -570,6 +578,11 @@ return; } + // Save the isolation state to prefs. On browser startup we may need access + // to the isolation state before WebAppDatabase has finished loading, so we + // duplicate this state in a pref to prevent blocking startup. + RecordOrRemoveAppIsolationState(profile_->GetPrefs(), *web_app); + AppId app_id = web_app->app_id(); std::unique_ptr<WebAppRegistryUpdate> update =
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index 2d123e2..aad8e6d 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/web_applications/daily_metrics_helper.h" #include "chrome/browser/web_applications/externally_managed_app_manager_impl.h" #include "chrome/browser/web_applications/file_utils_wrapper.h" +#include "chrome/browser/web_applications/isolation_prefs_utils.h" #include "chrome/browser/web_applications/manifest_update_manager.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/preinstalled_web_app_manager.h" @@ -360,6 +361,7 @@ WebAppPolicyManager::RegisterProfilePrefs(registry); SystemWebAppManager::RegisterProfilePrefs(registry); WebAppPrefsUtilsRegisterProfilePrefs(registry); + IsolationPrefsUtilsRegisterProfilePrefs(registry); RegisterInstallBounceMetricProfilePrefs(registry); RegisterDailyWebAppMetricsProfilePrefs(registry); }
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index e9da05f..45742ef 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1979,6 +1979,10 @@ // outlive the app installation and uninstallation. const char kWebAppsPreferences[] = "web_apps.web_app_ids"; +// Dictionary that maps the origin of a web app to other preferences related to +// its isolation requirements. +const char kWebAppsIsolationState[] = "web_apps.isolation_state"; + #if defined(OS_WIN) || defined(OS_MAC) || \ (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) // Dictionary that maps origins to web apps that can act as URL handlers.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index f57cd98e..842d073 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -669,6 +669,7 @@ extern const char kWebAppsDidMigrateDefaultChromeApps[]; extern const char kWebAppsUninstalledDefaultChromeApps[]; extern const char kWebAppsPreferences[]; +extern const char kWebAppsIsolationState[]; #if defined(OS_WIN) || defined(OS_MAC) || \ (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
diff --git a/chrome/renderer/autofill/form_control_click_detection_browsertest.cc b/chrome/renderer/autofill/form_control_click_detection_browsertest.cc index b684ece..0bf79e0 100644 --- a/chrome/renderer/autofill/form_control_click_detection_browsertest.cc +++ b/chrome/renderer/autofill/form_control_click_detection_browsertest.cc
@@ -18,6 +18,18 @@ namespace autofill { +namespace { + +FieldRendererId GetFieldRendererId(blink::WebElement element) { + blink::WebFormControlElement field = + element.To<blink::WebFormControlElement>(); + if (field.IsNull()) + return {}; + return FieldRendererId(field.UniqueRendererFormControlId()); +} + +} // namespace + class FormControlClickDetectionTest : public ChromeRenderViewTest { protected: void SetUp() override { @@ -54,14 +66,12 @@ } void ClearAutofillAgentTestState() { - autofill_agent_->last_clicked_form_control_element_for_testing_ = - blink::WebFormControlElement(); + autofill_agent_->last_clicked_form_control_element_for_testing_ = {}; autofill_agent_ ->last_clicked_form_control_element_was_focused_for_testing_ = false; } - const blink::WebFormControlElement& last_clicked_form_control_element() - const { + FieldRendererId last_clicked_form_control_element() const { return autofill_agent_->last_clicked_form_control_element_for_testing_; } @@ -71,7 +81,7 @@ } bool form_control_element_clicked_called() const { - return !last_clicked_form_control_element().IsNull(); + return !last_clicked_form_control_element().is_null(); } blink::WebElement text_; @@ -86,7 +96,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the text field again and verify that AutofillAgent knows about its @@ -94,7 +104,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_TRUE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the button, no notification should happen (this is not a text-input). @@ -110,7 +120,7 @@ EXPECT_TRUE(SimulateElementRightClick("text_1")); EXPECT_FALSE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_NE(text_, last_clicked_form_control_element()); + EXPECT_NE(GetFieldRendererId(text_), last_clicked_form_control_element()); } TEST_F(FormControlClickDetectionTest, InputFocusedAndClicked) { @@ -124,7 +134,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_TRUE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); } // Tests that AutofillAgent accepts form clicks for a textarea element which is @@ -135,7 +145,7 @@ EXPECT_TRUE(SimulateElementClick("textarea_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(textarea_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(textarea_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the text field again and verify that AutofillAgent knows about its @@ -143,7 +153,7 @@ EXPECT_TRUE(SimulateElementClick("textarea_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_TRUE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(textarea_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(textarea_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the button, no notification should happen (this is not a text-input). @@ -163,7 +173,7 @@ EXPECT_TRUE(SimulateElementClick("textarea_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_TRUE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(textarea_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(textarea_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); } @@ -177,7 +187,7 @@ SimulatePointClick(gfx::Point(30, 30)); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(textarea_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(textarea_), last_clicked_form_control_element()); } TEST_F(FormControlClickDetectionTest, ScaledTextareaTapped) { @@ -190,7 +200,7 @@ SimulateRectTap(gfx::Rect(30, 30, 30, 30)); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(textarea_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(textarea_), last_clicked_form_control_element()); } TEST_F(FormControlClickDetectionTest, DisabledInputClickedNoEvent) { @@ -200,7 +210,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the disabled element. @@ -215,7 +225,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); ClearAutofillAgentTestState(); // Click the disabled element and focus should change. @@ -228,7 +238,7 @@ EXPECT_TRUE(SimulateElementClick("text_1")); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); } TEST_F(FormControlClickDetectionTest, TapNearEdgeIsPageClick) { @@ -239,7 +249,7 @@ gfx::Vector2d(element_bounds.width() / 2 + 1, 0)); EXPECT_TRUE(form_control_element_clicked_called()); EXPECT_FALSE(last_clicked_form_control_element_was_focused()); - EXPECT_EQ(text_, last_clicked_form_control_element()); + EXPECT_EQ(GetFieldRendererId(text_), last_clicked_form_control_element()); } } // namespace autofill
diff --git a/chrome/renderer/cart/commerce_hint_agent.cc b/chrome/renderer/cart/commerce_hint_agent.cc index 2a4add8..882a07e 100644 --- a/chrome/renderer/cart/commerce_hint_agent.cc +++ b/chrome/renderer/cart/commerce_hint_agent.cc
@@ -379,6 +379,28 @@ return; if (navigation_url.DomainIs(kElectronicExpressDomain)) return; + if (IsCartHeuristicsImprovementEnabled()) { + if (navigation_url.DomainIs("abebooks.com")) + return; + if (navigation_url.DomainIs("abercrombie.com")) + return; + if (navigation_url.DomainIs(kAmazonDomain) && + url.host() != "fls-na.amazon.com") + return; + if (navigation_url.DomainIs("bestbuy.com")) + return; + if (navigation_url.DomainIs("containerstore.com")) + return; + if (navigation_url.DomainIs("gap.com") && url.DomainIs("granify.com")) + return; + if (navigation_url.DomainIs("kohls.com")) + return; + if (navigation_url.DomainIs("officedepot.com") && + url.DomainIs("chatid.com")) + return; + if (navigation_url.DomainIs("pier1.com")) + return; + } blink::WebHTTPBody body = request.HttpBody(); if (body.IsNull())
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 21bc479..0302b4e 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -142,8 +142,10 @@ #include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h" #include "third_party/blink/public/platform/url_conversion.h" #include "third_party/blink/public/platform/web_cache.h" +#include "third_party/blink/public/platform/web_content_security_policy_struct.h" #include "third_party/blink/public/platform/web_runtime_features.h" #include "third_party/blink/public/platform/web_security_origin.h" +#include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/platform/web_url_error.h" #include "third_party/blink/public/platform/web_url_request.h" @@ -195,6 +197,7 @@ #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h" #include "extensions/common/constants.h" #include "extensions/common/extension_urls.h" +#include "extensions/common/manifest_handlers/csp_info.h" #include "extensions/common/manifest_handlers/web_accessible_resources_info.h" #include "extensions/common/switches.h" #include "extensions/renderer/dispatcher.h" @@ -1657,3 +1660,28 @@ printing::SetAgent(user_agent); #endif } + +void ChromeContentRendererClient::AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + DCHECK(csp); + GURL gurl(url); + const extensions::Extension* extension = + extensions::RendererExtensionRegistry::Get()->GetExtensionOrAppByURL( + gurl); + if (!extension || !extension->is_extension() || + extension->manifest_version() < 3) { + return; + } + + // Append the default extension pages CSP to ensure the extension can't relax + // the default applied CSP through means like Service Worker. + const std::string& default_csp = + extensions::CSPInfo::GetDefaultMV3ExtensionPagesCSP(); + + csp->push_back({blink::WebString::FromUTF8(default_csp), + network::mojom::ContentSecurityPolicyType::kEnforce, + network::mojom::ContentSecurityPolicySource::kHTTP}); +#endif +}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index 4fb3926..b9b1841 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -55,6 +55,7 @@ namespace blink { class WebServiceWorkerContextProxy; enum class ProtocolHandlerSecurityLevel; +struct WebContentSecurityPolicyHeader; } namespace chrome { @@ -190,6 +191,9 @@ const std::string& name) override; bool IsSafeRedirectTarget(const GURL& url) override; void DidSetUserAgent(const std::string& user_agent) override; + void AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) override; #if BUILDFLAG(ENABLE_PLUGINS) static mojo::AssociatedRemote<chrome::mojom::PluginInfoHost>&
diff --git a/chrome/services/speech/cloud_speech_recognition_client.cc b/chrome/services/speech/cloud_speech_recognition_client.cc index bbbf509..3824981 100644 --- a/chrome/services/speech/cloud_speech_recognition_client.cc +++ b/chrome/services/speech/cloud_speech_recognition_client.cc
@@ -115,7 +115,8 @@ result = previous_result_; previous_result_ = result; - recognition_event_callback().Run(result, is_final); + recognition_event_callback().Run( + media::SpeechRecognitionResult(result, is_final)); } }
diff --git a/chrome/services/speech/cloud_speech_recognition_client.h b/chrome/services/speech/cloud_speech_recognition_client.h index 814a68d9..bd82c5f 100644 --- a/chrome/services/speech/cloud_speech_recognition_client.h +++ b/chrome/services/speech/cloud_speech_recognition_client.h
@@ -16,6 +16,7 @@ #include "components/speech/downstream_loader_client.h" #include "components/speech/upstream_loader.h" #include "components/speech/upstream_loader_client.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" namespace speech { @@ -38,8 +39,7 @@ public speech::DownstreamLoaderClient { public: using OnRecognitionEventCallback = - base::RepeatingCallback<void(const std::string& result, - const bool is_final)>; + base::RepeatingCallback<void(media::SpeechRecognitionResult)>; explicit CloudSpeechRecognitionClient( OnRecognitionEventCallback callback,
diff --git a/chrome/services/speech/cloud_speech_recognition_client_unittest.cc b/chrome/services/speech/cloud_speech_recognition_client_unittest.cc index e02cbf30..7ab83a8b 100644 --- a/chrome/services/speech/cloud_speech_recognition_client_unittest.cc +++ b/chrome/services/speech/cloud_speech_recognition_client_unittest.cc
@@ -68,7 +68,7 @@ void SetUp() override; protected: - void OnRecognitionEvent(const std::string& result, const bool is_final); + void OnRecognitionEvent(media::SpeechRecognitionResult result); void InjectDummyAudio(); @@ -164,10 +164,9 @@ } void CloudSpeechRecognitionClientUnitTest::OnRecognitionEvent( - const std::string& result, - const bool is_final) { - results_.push(result); - is_final_ = is_final; + media::SpeechRecognitionResult result) { + results_.push(result.transcription); + is_final_ = result.is_final; } void CloudSpeechRecognitionClientUnitTest::InjectDummyAudio() {
diff --git a/chrome/services/speech/soda/BUILD.gn b/chrome/services/speech/soda/BUILD.gn index 04249ac..f5770429 100644 --- a/chrome/services/speech/soda/BUILD.gn +++ b/chrome/services/speech/soda/BUILD.gn
@@ -20,6 +20,7 @@ deps = [ ":soda_api_proto", "//base", + "//media/mojo/mojom", ] if (is_chromeos_ash) {
diff --git a/chrome/services/speech/soda/cros_soda_client.cc b/chrome/services/speech/soda/cros_soda_client.cc index 4e32d9e..d04353b 100644 --- a/chrome/services/speech/soda/cros_soda_client.cc +++ b/chrome/services/speech/soda/cros_soda_client.cc
@@ -8,6 +8,30 @@ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h" #include "mojo/public/cpp/bindings/remote.h" +namespace { + +media::SpeechRecognitionResult GetSpeechRecognitionResultFromFinalEvent( + const chromeos::machine_learning::mojom::FinalResultPtr& final_event) { + media::SpeechRecognitionResult result; + result.transcription = final_event->final_hypotheses.front(); + result.is_final = true; + + if (!final_event->timing_event || !final_event->hypothesis_part) + return result; + + const auto& timing_event = final_event->timing_event; + media::TimingInformation timing; + timing.audio_start_time = timing_event->audio_start_time; + timing.audio_end_time = timing_event->event_end_time; + timing.hypothesis_parts = std::vector<media::HypothesisParts>(); + + for (const auto& part : final_event->hypothesis_part.value()) + timing.hypothesis_parts->emplace_back(part->text, part->alignment); + + return result; +} + +} // namespace namespace soda { CrosSodaClient::CrosSodaClient() : soda_client_(this) {} CrosSodaClient::~CrosSodaClient() = default; @@ -30,7 +54,7 @@ void CrosSodaClient::Reset( chromeos::machine_learning::mojom::SodaConfigPtr soda_config, - base::RepeatingCallback<void(const std::string&, bool)> callback) { + CrosSodaClient::TranscriptionResultCallback callback) { sample_rate_ = soda_config->sample_rate; channel_count_ = soda_config->channel_count; if (is_initialized_) { @@ -67,15 +91,13 @@ chromeos::machine_learning::mojom::SpeechRecognizerEventPtr event) { if (event->is_final_result()) { auto& final_result = event->get_final_result(); - if (!final_result->final_hypotheses.empty()) { - const std::string final_hyp = final_result->final_hypotheses.front(); - callback_.Run(final_hyp, true); - } + if (!final_result->final_hypotheses.empty()) + callback_.Run(GetSpeechRecognitionResultFromFinalEvent(final_result)); } else if (event->is_partial_result()) { auto& partial_result = event->get_partial_result(); if (!partial_result->partial_text.empty()) { const std::string partial_hyp = partial_result->partial_text.front(); - callback_.Run(partial_hyp, false); + callback_.Run(media::SpeechRecognitionResult(partial_hyp, false)); } } else if (!event->is_endpointer_event() || !event->is_audio_event()) { LOG(ERROR) << "Some kind of other soda event, ignoring completely. Tag is '"
diff --git a/chrome/services/speech/soda/cros_soda_client.h b/chrome/services/speech/soda/cros_soda_client.h index bfd0f3a..1762628 100644 --- a/chrome/services/speech/soda/cros_soda_client.h +++ b/chrome/services/speech/soda/cros_soda_client.h
@@ -5,12 +5,10 @@ #ifndef CHROME_SERVICES_SPEECH_SODA_CROS_SODA_CLIENT_H_ #define CHROME_SERVICES_SPEECH_SODA_CROS_SODA_CLIENT_H_ -#include <memory> -#include <string> - #include "base/callback.h" #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h" #include "chromeos/services/machine_learning/public/mojom/soda.mojom.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" @@ -24,6 +22,9 @@ CrosSodaClient(); ~CrosSodaClient() override; + using TranscriptionResultCallback = + base::RepeatingCallback<void(media::SpeechRecognitionResult event)>; + // Adds audio to this soda client. Only makes sense when initialized. // Eventually, asynchronous callbacks to the ::SodaClient overrides below are // executed. @@ -42,12 +43,12 @@ // Reset this client with the provided configuration, and send recognition // callbacks of (text, is_final) to the given callback. void Reset(chromeos::machine_learning::mojom::SodaConfigPtr soda_config, - base::RepeatingCallback<void(const std::string&, bool)> callback); + TranscriptionResultCallback callback); private: - // This callback is called with (text, is_final) whenever soda responds - // appropriately. - base::RepeatingCallback<void(const std::string&, bool)> callback_; + // This callback is called with (media::mojom::SpeechRecognitionResult) + // whenever soda responds appropriately. + TranscriptionResultCallback callback_; bool is_initialized_ = false; int sample_rate_ = 0; int channel_count_ = 0;
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc index 6e5d7a7..807484a 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.cc +++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -63,9 +63,10 @@ DCHECK(result.hypothesis_size()); static_cast<SpeechRecognitionRecognizerImpl*>(callback_handle) ->recognition_event_callback() - .Run( - std::string(result.hypothesis(0)), - result.result_type() == soda::chrome::SodaRecognitionResult::FINAL); + .Run(media::SpeechRecognitionResult( + result.hypothesis(0), + result.result_type() == + soda::chrome::SodaRecognitionResult::FINAL)); } if (response.soda_type() == soda::chrome::SodaResponse::LANGID) { @@ -129,12 +130,12 @@ } void SpeechRecognitionRecognizerImpl::OnRecognitionEvent( - const std::string& result, - const bool is_final) { + media::SpeechRecognitionResult event) { if (!client_remote_.is_bound()) return; + client_remote_->OnSpeechRecognitionRecognitionEvent( - media::mojom::SpeechRecognitionResult::New(result, is_final), + std::move(event), base::BindOnce(&SpeechRecognitionRecognizerImpl:: OnSpeechRecognitionRecognitionEventCallback, weak_factory_.GetWeakPtr()));
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.h b/chrome/services/speech/speech_recognition_recognizer_impl.h index 1c8c5d5..2fa6ea5 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.h +++ b/chrome/services/speech/speech_recognition_recognizer_impl.h
@@ -26,11 +26,12 @@ : public media::mojom::SpeechRecognitionRecognizer { public: using OnRecognitionEventCallback = - base::RepeatingCallback<void(const std::string& result, - const bool is_final)>; + base::RepeatingCallback<void(media::SpeechRecognitionResult event)>; + using OnLanguageIdentificationEventCallback = base::RepeatingCallback<void( const std::string& language, const media::mojom::ConfidenceLevel confidence_level)>; + SpeechRecognitionRecognizerImpl( mojo::PendingRemote<media::mojom::SpeechRecognitionRecognizerClient> remote, @@ -78,7 +79,8 @@ // Return the transcribed audio from the recognition event back to the caller // via the recognition event client. - void OnRecognitionEvent(const std::string& result, const bool is_final); + void OnRecognitionEvent(media::SpeechRecognitionResult event); + void OnLanguageIdentificationEvent( const std::string& language, const media::mojom::ConfidenceLevel confidence_level);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 9dac70d..d55f00d 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -593,6 +593,27 @@ ] } +if (is_android) { + template("telemetry_gpu_integration_test_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + "//content/test:telemetry_gpu_integration_test_support", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + telemetry_gpu_integration_test_android_template( + "telemetry_gpu_integration_test${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } +} + if (is_win) { source_set("credential_provider_test_utils") { testonly = true @@ -1337,6 +1358,7 @@ "../browser/browsing_data/navigation_entry_remover_browsertest.cc", "../browser/browsing_data/third_party_data_remover_browsertest.cc", "../browser/capability_delegation_browsertest.cc", + "../browser/cart/cart_service_browsertest.cc", "../browser/chrome_back_forward_cache_browsertest.cc", "../browser/chrome_content_browser_client_browsertest.cc", "../browser/chrome_do_not_track_browsertest.cc", @@ -1974,7 +1996,6 @@ # files will probably not be applicable. sources += [ "../browser/speech/extension_api/tts_extension_apitest.cc", - "../browser/speech/network_speech_recognizer_browsertest.cc", "../browser/speech/speech_recognition_browsertest.cc", ] deps += [ "//services/audio/public/cpp:test_support" ] @@ -3331,6 +3352,7 @@ "../browser/resources/chromeos/zip_archiver/test/zip_archiver_jstest.cc", "../browser/sessions/session_restore_browsertest_chromeos.cc", "../browser/signin/chromeos_mirror_account_consistency_browsertest.cc", + "../browser/speech/network_speech_recognizer_browsertest.cc", "../browser/speech/on_device_speech_recognizer_browsertest.cc", "../browser/ui/app_list/app_list_client_impl_browsertest.cc", "../browser/ui/app_list/app_service/app_service_app_item_browsertest.cc", @@ -3768,8 +3790,10 @@ } if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { - sources += - [ "../browser/ui/views/profiles/profile_picker_view_browsertest.cc" ] + sources += [ + "../browser/ui/views/profiles/profile_picker_view_browsertest.cc", + "../browser/ui/views/web_apps/web_app_url_handler_intent_picker_dialog_browsertest.cc", + ] } sources += metric_integration_sources @@ -3899,10 +3923,8 @@ } } -group("telemetry_perf_unittests") { +group("telemetry_perf_unittests_base") { testonly = true - deps = [ "//tools/perf:perf" ] - data = [ # For isolate contract. "//testing/scripts/run_telemetry_as_googletest.py", @@ -3921,16 +3943,72 @@ data_deps = [ "//testing:test_scripts_shared" ] } -group("telemetry_perf_tests") { +group("telemetry_perf_unittests") { testonly = true - deps = [ "//tools/perf/:perf" ] + data_deps = [ + ":telemetry_perf_unittests_base", + "//tools/perf:perf", + ] +} +if (is_android) { + template("telemetry_perf_unittests_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":telemetry_perf_unittests_base", + "//tools/perf:perf${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + telemetry_perf_unittests_android_template( + "telemetry_perf_unittests${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } +} + +group("telemetry_perf_tests_base") { + testonly = true data_deps = [ # Needed for isolate script to execute. "//testing:test_scripts_shared", ] } +group("telemetry_perf_tests") { + testonly = true + data_deps = [ + ":telemetry_perf_tests_base", + "//tools/perf/:perf", + ] +} + +if (is_android) { + template("telemetry_perf_tests_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":telemetry_perf_tests_base", + "//tools/perf/:perf${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + telemetry_perf_tests_android_template( + "telemetry_perf_tests${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } +} + group("ct_telemetry_perf_tests_without_chrome") { testonly = true deps = [ "//tools/perf/:perf_without_chrome" ] @@ -3950,8 +4028,12 @@ # New target that will replace telemetry_perf_tests when testing # is done. -template("performance_test_suite_template") { - forward_variables_from(invoker, [ "override_board" ]) +template("performance_test_suite_template_base") { + forward_variables_from(invoker, + [ + "override_board", + "data_deps", + ]) script_test(target_name) { run_under_python2 = true script = "//testing/scripts/run_performance_tests.py" @@ -3965,9 +4047,8 @@ args = [ "../../tools/perf/run_benchmark" ] } - data_deps = [ + data_deps += [ "//base:base_perftests", - "//chrome/test:telemetry_perf_tests", "//components:components_perftests", "//components/tracing:tracing_perftests", "//gpu:command_buffer_perftests", @@ -4001,9 +4082,40 @@ } } +template("performance_test_suite_template") { + forward_variables_from(invoker, [ "override_board" ]) + performance_test_suite_template_base(target_name) { + data_deps = [ "//chrome/test:telemetry_perf_tests" ] + } +} + +if (is_android) { + template("performance_test_suite_template_android") { + forward_variables_from(invoker, + [ + "override_board", + "telemetry_target_suffix", + ]) + performance_test_suite_template_base(target_name) { + data_deps = + [ "//chrome/test:telemetry_perf_tests${telemetry_target_suffix}" ] + } + } +} + performance_test_suite_template("performance_test_suite") { } +if (is_android) { + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + performance_test_suite_template_android( + "performance_test_suite${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } +} + # Generate performance_test_suite_${board} targets. # These set --board to ${board} instead of deriving it from the target. # This is useful for Lacros, where the generic build is deployed to @@ -4018,25 +4130,27 @@ } } -# Difference between this and performance_test_suite is that this runs a devil -# script before the build, to remove the system webview. See -# //testing/buildbot/gn_isolate_map.pyl -group("performance_webview_test_suite") { - testonly = true - deps = [ "//chrome/test:performance_test_suite" ] -} +if (is_android) { + # Difference between this and performance_test_suite is that this runs a devil + # script before the build, to remove the system webview. See + # //testing/buildbot/gn_isolate_map.pyl + group("performance_webview_test_suite") { + testonly = true + deps = [ "//chrome/test:performance_test_suite_android_webview" ] + } -group("performance_weblayer_test_suite") { - testonly = true - deps = [ "//chrome/test:performance_test_suite" ] -} + group("performance_weblayer_test_suite") { + testonly = true + deps = [ "//chrome/test:performance_test_suite_android_weblayer" ] + } -# Difference between this and telemetry_perf_tests is that this runs a devil -# script before the build, to remove the system webview. See -# //testing/buildbot/gn_isolate_map.pyl -group("telemetry_perf_webview_tests") { - testonly = true - deps = [ "//chrome/test:telemetry_perf_tests" ] + # Difference between this and telemetry_perf_tests is that this runs a devil + # script before the build, to remove the system webview. See + # //testing/buildbot/gn_isolate_map.pyl + group("telemetry_perf_webview_tests") { + testonly = true + deps = [ "//chrome/test:telemetry_perf_tests_android_webview" ] + } } config("disable_thinlto_cache_flags") { @@ -6818,6 +6932,7 @@ "../browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc", "../browser/ui/views/relaunch_notification/relaunch_required_timer_internal_unittest.cc", "../browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl_unittest.cc", + "../browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_bubble_view_unittest.cc", "../browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views_unittest.cc", "../browser/ui/views/tabs/color_picker_view_unittest.cc", "../browser/ui/views/tabs/fake_base_tab_strip_controller.cc", @@ -8469,9 +8584,8 @@ } if (is_mac || is_win || is_android) { - group("rendering_representative_perf_tests") { + group("rendering_representative_perf_tests_base") { testonly = true - deps = [ "//tools/perf/chrome_telemetry_build:telemetry_chrome_test" ] data = [ "//build/android/pylib", "//chrome/test/data/perf", @@ -8482,6 +8596,35 @@ ] data_deps = [ "//testing:test_scripts_shared" ] } + + group("rendering_representative_perf_tests") { + testonly = true + data_deps = [ + ":rendering_representative_perf_tests_base", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + ] + } + + if (is_android) { + template("rendering_representative_perf_tests_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":rendering_representative_perf_tests_base", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + rendering_representative_perf_tests_android_template( + "rendering_representative_perf_tests${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } + } } if (is_win) {
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index a3c931c..a59eddae 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -67,8 +67,6 @@ #include "components/google/core/common/google_util.h" #include "components/os_crypt/os_crypt_mocker.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_types.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" @@ -600,11 +598,9 @@ #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) { - content::WindowedNotificationObserver observer( - content::NOTIFICATION_LOAD_STOP, - content::NotificationService::AllSources()); - chrome::AddSelectedTabWithURL(browser, GURL(url::kAboutBlankURL), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL); + content::WebContents* blank_tab = chrome::AddSelectedTabWithURL( + browser, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_AUTO_TOPLEVEL); + content::TestNavigationObserver observer(blank_tab); observer.Wait(); browser->window()->Show();
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/extension_page.html b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/extension_page.html new file mode 100644 index 0000000..ac60f7ff --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/extension_page.html
@@ -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. +--> + +<!DOCTYPE html> +<script> + scriptExecuted = true; +</script>
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/manifest.json b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/manifest.json new file mode 100644 index 0000000..ccd592c3 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/manifest.json
@@ -0,0 +1,6 @@ +{ + "name": "Extension CSP modification", + "version": "1.0", + "manifest_version": 3, + "background": {"service_worker": "service_worker.js"} +}
diff --git a/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/service_worker.js b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/service_worker.js new file mode 100644 index 0000000..260f928 --- /dev/null +++ b/chrome/test/data/extensions/api_test/service_worker/worker_based_background/extension_csp_modification/service_worker.js
@@ -0,0 +1,29 @@ +// 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. + +self.addEventListener('fetch', event => { + if (!event.request.url.endsWith('extension_page.html')) + return; + + // Strip the CSP header from the request. + return event.respondWith( + fetch(event.request).then(response => { + const kCSPHeader = 'content-security-policy'; + chrome.test.sendMessage(response.headers.get(kCSPHeader)); + let updatedHeaders = new Headers(response.headers); + updatedHeaders.delete(kCSPHeader); + let init = { + status: response.status, + statusText: response.statusText, + headers: updatedHeaders + }; + return new Response(response.body, init); + }) + ); +}); + +self.addEventListener('activate', event => { + chrome.test.sendMessage('ready'); + return self.clients.claim(); +});
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js index 6d2b5eb..1893546b 100644 --- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js +++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
@@ -35,7 +35,14 @@ } }; -TEST_F('EmojiPickerMainTest', 'All', function() { +// Flaky on debug builds, see https://crbug.com/1216145 +GEN('#if !defined(NDEBUG)'); +GEN('#define MAYBE_All DISABLED_All'); +GEN('#else'); +GEN('#define MAYBE_All All'); +GEN('#endif'); + +TEST_F('EmojiPickerMainTest', 'MAYBE_All', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js index 56cd05b..ffd62dd 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js
@@ -145,16 +145,69 @@ }); }); - test('UpdateChromeDefaultUndefined', () => { - return service.updateChrome().then((error) => { - assertEquals(error, undefined); + test('UpdateChromeOk', () => { + let states = [ + {state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk}, + {state: RmaState.kChooseDestination, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.updateChrome().then((state) => { + assertEquals(state.state, RmaState.kChooseDestination); + assertEquals(state.error, RmadErrorCode.kOk); }); }); - test('SetUpdateChromeResultUpdatesResult', () => { - service.setUpdateChromeResult(RmadErrorCode.kRequestInvalid); - return service.updateChrome().then((error) => { - assertEquals(error.error, RmadErrorCode.kRequestInvalid); + test('UpdateChromeWhenRmaNotRequired', () => { + return service.updateChrome().then((state) => { + assertEquals(state.state, RmaState.kUnknown); + assertEquals(state.error, RmadErrorCode.kRmaNotRequired); + }); + }); + + test('UpdateChromeWrongStateFails', () => { + let states = [ + {state: RmaState.kWelcomeScreen, error: RmadErrorCode.kOk}, + {state: RmaState.kChooseDestination, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.updateChrome().then((state) => { + assertEquals(state.state, RmaState.kWelcomeScreen); + assertEquals(state.error, RmadErrorCode.kRequestInvalid); + }); + }); + + test('UpdateChromeSkippedOk', () => { + let states = [ + {state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk}, + {state: RmaState.kChooseDestination, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.updateChromeSkipped().then((state) => { + assertEquals(state.state, RmaState.kChooseDestination); + assertEquals(state.error, RmadErrorCode.kOk); + }); + }); + + test('UpdateChromeSkippedWhenRmaNotRequired', () => { + return service.updateChrome().then((state) => { + assertEquals(state.state, RmaState.kUnknown); + assertEquals(state.error, RmadErrorCode.kRmaNotRequired); + }); + }); + + test('UpdateChromeSkippedWrongStateFails', () => { + let states = [ + {state: RmaState.kWelcomeScreen, error: RmadErrorCode.kOk}, + {state: RmaState.kChooseDestination, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.updateChrome().then((state) => { + assertEquals(state.state, RmaState.kWelcomeScreen); + assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); });
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js index 0098ba73..16901d6 100644 --- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js +++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -772,15 +772,6 @@ return destination_dialog_cros_test.suiteName; } - /** @override */ - get featureList() { - const featureList = super.featureList || []; - const kPrintServerScaling = ['chromeos::features::kPrintServerScaling']; - featureList.enabled = featureList.enabled ? - featureList.enabled.concat(kPrintServerScaling) : - kPrintServerScaling; - return featureList; - } }; TEST_F('PrintPreviewDestinationDialogCrosTest', 'PrinterList', function() { @@ -1124,16 +1115,6 @@ get suiteName() { return destination_item_test_cros.suiteName; } - - /** @override */ - get featureList() { - const kPrinterStatusDialog = ['chromeos::features::kPrinterStatusDialog']; - const featureList = super.featureList || []; - featureList.enabled = featureList.enabled ? - featureList.enabled.concat(kPrinterStatusDialog) : - kPrinterStatusDialog; - return featureList; - } }; TEST_F(
diff --git a/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js b/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js index 1ca11ab..45476fd 100644 --- a/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js +++ b/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js
@@ -20,17 +20,19 @@ return (el !== null) && (el.style.display !== 'none'); } - function initWithPSimOnlyLocked(flag_enabled) { + function initWithPSimOnly(flagEnabled, isLocked) { const mojom = chromeos.networkConfig.mojom; const kTestIccid1 = '00000000000000000000'; + const simLockStatus = isLocked ? {lockType: 'sim-pin'} : {lockType: ''}; + netSummaryItem.setProperties({ - isUpdatedCellularUiEnabled_: flag_enabled, + isUpdatedCellularUiEnabled_: flagEnabled, deviceState: { deviceState: mojom.DeviceStateType.kEnabled, type: mojom.NetworkType.kCellular, simAbsent: false, - simLockStatus: {lockType: 'sim-pin'}, + simLockStatus: simLockStatus, simInfos: [{slot_id: 1, eid: '', iccid: kTestIccid1, isPrimary: true}], }, activeNetworkState: { @@ -44,12 +46,12 @@ Polymer.dom.flush(); } - function initWithESimLocked(flag_enabled) { + function initWithESimLocked(flagEnabled) { const mojom = chromeos.networkConfig.mojom; const kTestIccid1 = '00000000000000000000'; netSummaryItem.setProperties({ - isUpdatedCellularUiEnabled_: flag_enabled, + isUpdatedCellularUiEnabled_: flagEnabled, deviceState: { deviceState: mojom.DeviceStateType.kEnabled, type: mojom.NetworkType.kCellular, @@ -241,49 +243,65 @@ }); test('Mobile data toggle shown on locked device, flag on', function() { - initWithESimLocked(/*flag_enabled = */ true); + initWithESimLocked(/*flagEnabled = */ true); assertNotEquals(netSummaryItem.$$('#deviceEnabledButton'), null); + assertTrue(doesElementExist('#deviceEnabledButton')); }); test('Mobile data toggle shown on locked device, flag off', function() { - initWithESimLocked(/*flag_enabled = */ false); + initWithESimLocked(/*flagEnabled = */ false); assertEquals(netSummaryItem.$$('#deviceEnabledButton'), null); + assertFalse(doesElementExist('#deviceEnabledButton')); }); test('pSIM-only locked device, show SIM locked UI, flag off', function() { - initWithPSimOnlyLocked(/*flag_enabled = */ false); + initWithPSimOnly(/*flagEnabled = */ false, /*isLocked = */ true); assertTrue(doesElementExist('network-siminfo')); assertFalse(netSummaryItem.$$('#networkState') .classList.contains('locked-warning-message')); assertTrue( netSummaryItem.$$('#networkState').classList.contains('network-state')); + assertFalse(doesElementExist('#deviceEnabledButton')); }); test('eSIM enabled locked device, show SIM locked UI, flag off', function() { - initWithESimLocked(/*flag_enabled = */ false); + initWithESimLocked(/*flagEnabled = */ false); assertTrue(doesElementExist('network-siminfo')); assertFalse(netSummaryItem.$$('#networkState') .classList.contains('locked-warning-message')); assertTrue( netSummaryItem.$$('#networkState').classList.contains('network-state')); + assertFalse(doesElementExist('#deviceEnabledButton')); }); test('pSIM-only locked device, show SIM locked UI, flag on', function() { - initWithPSimOnlyLocked(/*flag_enabled = */ true); + initWithPSimOnly(/*flagEnabled = */ true, /*isLocked = */ true); assertTrue(doesElementExist('network-siminfo')); assertTrue(netSummaryItem.$$('#networkState') .classList.contains('locked-warning-message')); assertFalse( netSummaryItem.$$('#networkState').classList.contains('network-state')); + assertFalse(doesElementExist('#deviceEnabledButton')); }); - test('eSIM enabled locked device, show SIM locked UI, flag on', function() { - initWithESimLocked(/*flag_enabled = */ true); + test('pSIM-only locked device, no SIM locked UI, flag on', function() { + initWithPSimOnly(/*flagEnabled = */ true, /*isLocked = */ false); assertFalse(doesElementExist('network-siminfo')); assertFalse(netSummaryItem.$$('#networkState') .classList.contains('locked-warning-message')); assertTrue( netSummaryItem.$$('#networkState').classList.contains('network-state')); + assertTrue(doesElementExist('#deviceEnabledButton')); + }); + + test('eSIM enabled locked device, show SIM locked UI, flag on', function() { + initWithESimLocked(/*flagEnabled = */ true); + assertFalse(doesElementExist('network-siminfo')); + assertFalse(netSummaryItem.$$('#networkState') + .classList.contains('locked-warning-message')); + assertTrue( + netSummaryItem.$$('#networkState').classList.contains('network-state')); + assertTrue(doesElementExist('#deviceEnabledButton')); }); test(
diff --git a/chrome/test/data/webui/tab_search/BUILD.gn b/chrome/test/data/webui/tab_search/BUILD.gn index 7b5f807..947bb3e 100644 --- a/chrome/test/data/webui/tab_search/BUILD.gn +++ b/chrome/test/data/webui/tab_search/BUILD.gn
@@ -19,6 +19,9 @@ "js_module_root=" + rebase_path( "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/tab_search", root_build_dir), + "js_module_root=" + rebase_path( + "$root_gen_dir/mojom-webui/components/tab_groups/public/mojom", + root_build_dir), ] deps = [ ":bimap_test",
diff --git a/chrome/test/data/webui/tab_search/tab_search_app_test.js b/chrome/test/data/webui/tab_search/tab_search_app_test.js index cfda003..e1e5d2e 100644 --- a/chrome/test/data/webui/tab_search/tab_search_app_test.js +++ b/chrome/test/data/webui/tab_search/tab_search_app_test.js
@@ -3,12 +3,12 @@ // found in the LICENSE file. import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; -import {ProfileData, Tab, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchSearchField} from 'chrome://tab-search.top-chrome/tab_search.js'; +import {ProfileData, Tab, TabGroup, TabGroupColor, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchSearchField} from 'chrome://tab-search.top-chrome/tab_search.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; import {flushTasks, waitAfterNextRender} from '../../test_util.m.js'; -import {generateSampleDataFromSiteNames, generateSampleTabsFromSiteNames, SAMPLE_RECENTLY_CLOSED_DATA, SAMPLE_WINDOW_DATA, SAMPLE_WINDOW_HEIGHT, sampleData} from './tab_search_test_data.js'; +import {generateSampleDataFromSiteNames, generateSampleTabsFromSiteNames, SAMPLE_RECENTLY_CLOSED_DATA, SAMPLE_WINDOW_DATA, SAMPLE_WINDOW_HEIGHT, sampleData, sampleToken} from './tab_search_test_data.js'; import {initLoadTimeDataWithDefaults} from './tab_search_test_helper.js'; import {TestTabSearchApiProxy} from './test_tab_search_api_proxy.js'; @@ -64,7 +64,8 @@ test('return all open and recently closed tabs', async () => { await setupTest({ windows: SAMPLE_WINDOW_DATA, - recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA + recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA, + tabGroups: [], }); tabSearchApp.shadowRoot.querySelector('#tabsList') .ensureAllDomItemsAvailable(); @@ -82,6 +83,7 @@ }], recentlyClosedTabs: generateSampleTabsFromSiteNames( ['RecentlyClosedTab1', 'RecentlyClosedTab2'], false), + tabGroups: [], }, {recentlyClosedDefaultItemDisplayCount: 1}); @@ -97,7 +99,8 @@ test('Search text changes tab items', async () => { await setupTest({ windows: SAMPLE_WINDOW_DATA, - recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA + recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA, + tabGroups: [], }); const searchField = /** @type {!TabSearchSearchField} */ (tabSearchApp.shadowRoot.querySelector('#searchField')); @@ -129,8 +132,11 @@ title: 'Google', url: 'https://www.google.com', }; - await setupTest( - {windows: [{active: true, tabs: [tabData]}], recentlyClosedTabs: []}); + await setupTest({ + windows: [{active: true, tabs: [tabData]}], + recentlyClosedTabs: [], + tabGroups: [] + }); const tabSearchItem = /** @type {!HTMLElement} */ (tabSearchApp.shadowRoot.querySelector('#tabsList') @@ -169,7 +175,8 @@ url: 'https://www.google.com', }] }], - recentlyClosedTabs: [tabData] + recentlyClosedTabs: [tabData], + tabGroups: [], }); let tabSearchItem = /** @type {!HTMLElement} */ @@ -181,8 +188,11 @@ }); test('Keyboard navigation on an empty list', async () => { - await setupTest( - {windows: [{active: true, tabs: []}], recentlyClosedTabs: []}); + await setupTest({ + windows: [{active: true, tabs: []}], + recentlyClosedTabs: [], + tabGroups: [] + }); const searchField = /** @type {!TabSearchSearchField} */ (tabSearchApp.shadowRoot.querySelector("#searchField")); @@ -265,7 +275,7 @@ await setupTest(sampleData()); verifyTabIds(queryRows(), [1, 5, 6, 2, 3, 4]); testProxy.getCallbackRouterRemote().tabsChanged( - {windows: [], recentlyClosedTabs: []}); + {windows: [], recentlyClosedTabs: [], tabGroups: []}); await flushTasks(); verifyTabIds(queryRows(), []); assertEquals(-1, tabSearchApp.getSelectedIndex()); @@ -280,14 +290,18 @@ keyDownOn(searchField, 0, [], 'ArrowDown'); assertEquals(1, tabSearchApp.getSelectedIndex()); - testProxy.getCallbackRouterRemote().tabsChanged( - {windows: [testData.windows[0]], recentlyClosedTabs: []}); + testProxy.getCallbackRouterRemote().tabsChanged({ + windows: [testData.windows[0]], + recentlyClosedTabs: [], + tabGroups: [] + }); await flushTasks(); assertEquals(1, tabSearchApp.getSelectedIndex()); testProxy.getCallbackRouterRemote().tabsChanged({ windows: [{active: true, tabs: [testData.windows[0].tabs[0]]}], - recentlyClosedTabs: [] + recentlyClosedTabs: [], + tabGroups: [], }); await flushTasks(); assertEquals(0, tabSearchApp.getSelectedIndex()); @@ -495,14 +509,16 @@ // Move active tab to the bottom of the list. await setupTest({ windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}], - recentlyClosedTabs: [] + recentlyClosedTabs: [], + tabGroups: [], }); verifyTabIds(queryRows(), [3, 1, 2]); await setupTest( { windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}], - recentlyClosedTabs: [] + recentlyClosedTabs: [], + tabGroups: [], }, {'moveActiveTabToBottom': false}); verifyTabIds(queryRows(), [2, 3, 1]); @@ -524,4 +540,36 @@ assertEquals(3, testProxy.getCallCount('closeUI')); }); + + test('Tab associated with TabGroup data', async () => { + const token = sampleToken(1, 1); + const tabs = [ + { + index: 0, + tabId: 1, + groupId: token, + title: 'Google', + url: 'https://www.google.com', + lastActiveTimeTicks: {internalValue: BigInt(2)}, + lastActiveElapsedText: '', + }, + ]; + const tabGroup = /** @type {!TabGroup} */ ({ + id: token, + color: TabGroupColor.kBlue, + title: 'Search Engines', + }); + + await setupTest({ + windows: [{active: true, height: SAMPLE_WINDOW_HEIGHT, tabs}], + recentlyClosedTabs: [], + tabGroups: [tabGroup], + }); + + let tabSearchItem = /** @type {!HTMLElement} */ ( + tabSearchApp.shadowRoot.querySelector('#tabsList') + .querySelector('tab-search-item[id="1"]')); + assertEquals('Google', tabSearchItem.data.tab.title); + assertEquals('Search Engines', tabSearchItem.data.tabGroup.title); + }); });
diff --git a/chrome/test/data/webui/tab_search/tab_search_item_test.js b/chrome/test/data/webui/tab_search/tab_search_item_test.js index 3ada5c2..5daf57f 100644 --- a/chrome/test/data/webui/tab_search/tab_search_item_test.js +++ b/chrome/test/data/webui/tab_search/tab_search_item_test.js
@@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Tab, TabData, TabItemType, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js'; +import {Tab, TabData, TabGroup, TabGroupColor, TabItemType, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js'; + import {assertDeepEquals, assertEquals, assertNotEquals} from '../../chai_assert.js'; import {flushTasks} from '../../test_util.m.js'; +import {sampleToken} from './tab_search_test_data.js'; + suite('TabSearchItemTest', () => { /** @type {!TabSearchItem} */ let tabSearchItem; @@ -104,4 +107,38 @@ tabSearchItem.shadowRoot.querySelector('cr-icon-button')); assertEquals(null, tabSearchItemCloseButton); }); + + test('GroupDetailsPresence', async () => { + const token = sampleToken(1, 1); + const tab = /** @type {!Tab} */ ({ + active: true, + index: 0, + isDefaultFavicon: true, + lastActiveTimeTicks: {internalValue: BigInt(0)}, + pinned: false, + showIcon: true, + tabId: 0, + groupId: token, + url: 'https://example.com', + title: 'Example.com site', + }); + + const tabGroup = /** @type {!TabGroup} */ ({ + id: token, + color: TabGroupColor.kBlue, + title: 'Examples', + }); + + await setupTest(/** @type {!TabData} */ ( + {hostname: 'example', tab, type: TabItemType.OPEN, tabGroup})); + const groupDotElement = tabSearchItem.shadowRoot.querySelector('#groupDot'); + assertNotEquals(null, groupDotElement); + const groupDotComputedStyle = getComputedStyle(groupDotElement); + assertEquals( + groupDotComputedStyle.getPropertyValue('--tab-group-color-blue'), + groupDotComputedStyle.getPropertyValue('--group-dot-color')); + + assertNotEquals( + null, tabSearchItem.shadowRoot.querySelector('#groupTitle')); + }); });
diff --git a/chrome/test/data/webui/tab_search/tab_search_test_data.js b/chrome/test/data/webui/tab_search/tab_search_test_data.js index a4642728..a277789a 100644 --- a/chrome/test/data/webui/tab_search/tab_search_test_data.js +++ b/chrome/test/data/webui/tab_search/tab_search_test_data.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {Token} from 'chrome://resources/mojo/mojo/public/mojom/base/token.mojom-webui.js'; + /** @type {number} */ export const SAMPLE_WINDOW_HEIGHT = 448; @@ -89,7 +91,7 @@ /** @return {!Array} */ export function sampleData() { - return {windows: SAMPLE_WINDOW_DATA, recentlyClosedTabs: []}; + return {windows: SAMPLE_WINDOW_DATA, recentlyClosedTabs: [], tabGroups: []}; } /** @@ -136,6 +138,21 @@ height: SAMPLE_WINDOW_HEIGHT, tabs: generateSampleTabsFromSiteNames(siteNames) }], - recentlyClosedTabs: [] + recentlyClosedTabs: [], + tabGroups: [], }; } + +/** + * @param {!bigint} high + * @param {!bigint} low + * @return {!Token} + */ +export function sampleToken(high, low) { + const token = new Token(); + token.high = high; + token.low = low; + Object.freeze(token); + + return token; +}
diff --git a/chrome/test/media_router/BUILD.gn b/chrome/test/media_router/BUILD.gn index 5d78dc1..d2c5191 100644 --- a/chrome/test/media_router/BUILD.gn +++ b/chrome/test/media_router/BUILD.gn
@@ -144,14 +144,42 @@ } if (enable_downstream_media_tests) { - group("media_router_perf_tests") { + group("media_router_perf_tests_base") { testonly = true data = [ "$root_out_dir/mr_extension/", "internal/", "telemetry/", ] - deps = [ "//tools/perf:perf" ] data_deps = [ "//tools/perf/contrib/media_router_benchmarks:telemetry_extension_resources" ] } + + group("media_router_perf_tests") { + testonly = true + data_deps = [ + ":media_router_perf_tests_base", + "//tools/perf:perf", + ] + } + + if (is_android) { + template("media_router_perf_tests_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":media_router_perf_tests_base", + "//tools/perf:perf${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + media_router_perf_tests_android_template( + "media_router_perf_tests${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } + } + } }
diff --git a/chromecast/browser/cast_content_gesture_handler_test.cc b/chromecast/browser/cast_content_gesture_handler_test.cc index fe532b3..87ee316 100644 --- a/chromecast/browser/cast_content_gesture_handler_test.cc +++ b/chromecast/browser/cast_content_gesture_handler_test.cc
@@ -40,12 +40,6 @@ constexpr gfx::Point kOngoingRightGesturePoint1(400, 50); constexpr gfx::Point kRightGestureEndPoint(200, 60); -ACTION_TEMPLATE(InvokeCallbackArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(p0)) { - std::move(std::get<k>(args)).Run(p0); -} - } // namespace class CastContentGestureHandlerTest : public testing::Test { @@ -70,7 +64,8 @@ EXPECT_CALL(*delegate_, GestureProgress(Eq(GestureType::GO_BACK), Eq(kOngoingBackGesturePoint1))); EXPECT_CALL(*delegate_, ConsumeGesture(Eq(GestureType::GO_BACK), _)) - .WillRepeatedly(InvokeCallbackArgument<1>(true)); + .WillRepeatedly( + [](auto, auto callback) { std::move(callback).Run(true); }); dispatcher_.CanHandleSwipe(CastSideSwipeOrigin::LEFT); dispatcher_.HandleSideSwipe(CastSideSwipeEvent::BEGIN, CastSideSwipeOrigin::LEFT, kLeftSidePoint); @@ -117,7 +112,8 @@ EXPECT_CALL(*delegate_, GestureProgress(Eq(GestureType::GO_BACK), Eq(kPastTheEndPoint1))); EXPECT_CALL(*delegate_, ConsumeGesture(Eq(GestureType::GO_BACK), _)) - .WillRepeatedly(InvokeCallbackArgument<1>(true)); + .WillRepeatedly( + [](auto, auto callback) { std::move(callback).Run(true); }); dispatcher_.CanHandleSwipe(CastSideSwipeOrigin::LEFT); dispatcher_.HandleSideSwipe(CastSideSwipeEvent::BEGIN, CastSideSwipeOrigin::LEFT, kLeftSidePoint); @@ -215,7 +211,8 @@ EXPECT_CALL(*delegate_, GestureProgress(Eq(GestureType::TOP_DRAG), Eq(kOngoingTopGesturePoint1))); EXPECT_CALL(*delegate_, ConsumeGesture(Eq(GestureType::TOP_DRAG), _)) - .WillRepeatedly(InvokeCallbackArgument<1>(true)); + .WillRepeatedly( + [](auto, auto callback) { std::move(callback).Run(true); }); dispatcher_.CanHandleSwipe(CastSideSwipeOrigin::TOP); dispatcher_.HandleSideSwipe(CastSideSwipeEvent::BEGIN, CastSideSwipeOrigin::TOP, kTopSidePoint); @@ -238,7 +235,8 @@ EXPECT_CALL(*delegate_, GestureProgress(Eq(GestureType::RIGHT_DRAG), Eq(kOngoingRightGesturePoint1))); EXPECT_CALL(*delegate_, ConsumeGesture(Eq(GestureType::RIGHT_DRAG), _)) - .WillRepeatedly(InvokeCallbackArgument<1>(true)); + .WillRepeatedly( + [](auto, auto callback) { std::move(callback).Run(true); }); dispatcher_.CanHandleSwipe(CastSideSwipeOrigin::RIGHT); dispatcher_.HandleSideSwipe(CastSideSwipeEvent::BEGIN, CastSideSwipeOrigin::RIGHT, kRightSidePoint);
diff --git a/chromecast/browser/test/mock_cast_content_window_delegate.cc b/chromecast/browser/test/mock_cast_content_window_delegate.cc index 86e6725..f8430963 100644 --- a/chromecast/browser/test/mock_cast_content_window_delegate.cc +++ b/chromecast/browser/test/mock_cast_content_window_delegate.cc
@@ -10,13 +10,6 @@ MockCastContentWindowDelegate::~MockCastContentWindowDelegate() = default; -void MockCastContentWindowDelegate::ConsumeGesture( - GestureType gesture_type, - GestureHandledCallback handled_callback) { - ConsumeGesture(gesture_type, - base::AdaptCallbackForRepeating(std::move(handled_callback))); -} - std::string MockCastContentWindowDelegate::GetId() { return "mockContentWindowDelegate"; }
diff --git a/chromecast/browser/test/mock_cast_content_window_delegate.h b/chromecast/browser/test/mock_cast_content_window_delegate.h index 71f8f65..9a5fcdb 100644 --- a/chromecast/browser/test/mock_cast_content_window_delegate.h +++ b/chromecast/browser/test/mock_cast_content_window_delegate.h
@@ -21,15 +21,12 @@ MOCK_METHOD1(CanHandleGesture, bool(GestureType gesture_type)); MOCK_METHOD2(ConsumeGesture, void(GestureType gesture_type, - base::RepeatingCallback<void(bool)> handled_callback)); + GestureHandledCallback handled_callback)); MOCK_METHOD1(CancelGesture, void(GestureType gesture_type)); MOCK_METHOD2(GestureProgress, void(GestureType gesture_type, const gfx::Point& touch_location)); - void ConsumeGesture(GestureType gesture_type, - GestureHandledCallback handled_callback) override; - std::string GetId() override; };
diff --git a/chromecast/media/api/cma_backend_factory.h b/chromecast/media/api/cma_backend_factory.h index 19a4e09..6ab51689 100644 --- a/chromecast/media/api/cma_backend_factory.h +++ b/chromecast/media/api/cma_backend_factory.h
@@ -7,15 +7,24 @@ #include <memory> +namespace service_manager { +class Connector; +} // namespace service_manager + namespace chromecast { namespace media { class CmaBackend; +class MediaPipelineBackendManager; struct MediaPipelineDeviceParams; // Abstract base class to create CmaBackend. class CmaBackendFactory { public: + static std::unique_ptr<CmaBackendFactory> Create( + MediaPipelineBackendManager* media_pipeline_backend_manager, + std::unique_ptr<service_manager::Connector> connector); + virtual ~CmaBackendFactory() = default; // Creates a CMA backend. Must be called on the same thread as
diff --git a/chromecast/media/cdm/cast_cdm.cc b/chromecast/media/cdm/cast_cdm.cc index 4511bbdd..37f181e 100644 --- a/chromecast/media/cdm/cast_cdm.cc +++ b/chromecast/media/cdm/cast_cdm.cc
@@ -149,8 +149,9 @@ session_message_cb_.Run(session_id, message_type, message); } -void CastCdm::OnSessionClosed(const std::string& session_id) { - session_closed_cb_.Run(session_id); +void CastCdm::OnSessionClosed(const std::string& session_id, + ::media::CdmSessionClosedReason reason) { + session_closed_cb_.Run(session_id, reason); } void CastCdm::OnSessionKeysChange(const std::string& session_id,
diff --git a/chromecast/media/cdm/cast_cdm.h b/chromecast/media/cdm/cast_cdm.h index 89711db..7debfde3 100644 --- a/chromecast/media/cdm/cast_cdm.h +++ b/chromecast/media/cdm/cast_cdm.h
@@ -77,7 +77,8 @@ void OnSessionMessage(const std::string& session_id, const std::vector<uint8_t>& message, ::media::CdmMessageType message_type); - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + ::media::CdmSessionClosedReason reason); void OnSessionKeysChange(const std::string& session_id, bool newly_usable_keys, ::media::CdmKeysInfo keys_info);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 1998f8ec..f7337879 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -14010.0.0 \ No newline at end of file +14011.0.0 \ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js index dcba8617..e6192f5 100644 --- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js +++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -209,8 +209,7 @@ }); await video.play(); this.video_.parentElement.replaceChild(tpl, this.video_); - this.video_.removeAttribute('srcObject'); - this.video_.load(); + this.video_.srcObject = null; this.video_ = video; video.addEventListener('resize', () => this.onIntrinsicSizeChanged_()); video.addEventListener(
diff --git a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc index 121f2575..c3ea05e 100644 --- a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc +++ b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.cc
@@ -334,7 +334,9 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(2) << __func__; cdm_session_tracker_.RemoveSession(session_id); - session_closed_cb_.Run(session_id); + // TODO(crbug.com/1208618): Update cdm::mojom::ContentDecryptionModuleClient + // to support CdmSessionClosedReason. + session_closed_cb_.Run(session_id, media::CdmSessionClosedReason::kClose); } void ContentDecryptionModuleAdapter::OnSessionKeysChange( @@ -536,7 +538,8 @@ ContentDecryptionModuleAdapter::~ContentDecryptionModuleAdapter() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(2) << __func__; - cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_); + cdm_session_tracker_.CloseRemainingSessions( + session_closed_cb_, media::CdmSessionClosedReason::kCdmUnavailable); } void ContentDecryptionModuleAdapter::OnConnectionError() { @@ -553,7 +556,8 @@ // any open sessions. cdm_promise_adapter_.Clear( media::CdmPromiseAdapter::ClearReason::kConnectionError); - cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_); + cdm_session_tracker_.CloseRemainingSessions( + session_closed_cb_, media::CdmSessionClosedReason::kCdmUnavailable); } void ContentDecryptionModuleAdapter::RejectTrackedPromise(
diff --git a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter_unittest.cc b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter_unittest.cc index 30447d8..a26bc0d 100644 --- a/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter_unittest.cc +++ b/chromeos/components/cdm_factory_daemon/content_decryption_module_adapter_unittest.cc
@@ -311,7 +311,7 @@ media::CdmSessionType::kTemporary, media::EmeInitDataType::CENC, ToVector(kFakeEmeInitData), std::move(promise)); // We should also be getting a session closed callback for any open sessions. - EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId1)); + EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId1, _)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(session_id, kFakeSessionId1); } @@ -336,7 +336,7 @@ TEST_F(ContentDecryptionModuleAdapterTest, LoadSession_Success) { LoadSession(); // We should also be getting a session closed callback for any open sessions. - EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2)); + EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2, _)); } TEST_F(ContentDecryptionModuleAdapterTest, UpdateSession_Failure) { @@ -428,7 +428,7 @@ TEST_F(ContentDecryptionModuleAdapterTest, OnSessionClosed) { LoadSession(); - EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2)); + EXPECT_CALL(mock_session_closed_cb_, Run(kFakeSessionId2, _)); cdm_adapter_->OnSessionClosed(kFakeSessionId2); }
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn index e29dbe1..98dd4a9 100644 --- a/chromeos/crosapi/mojom/BUILD.gn +++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -30,6 +30,7 @@ "metrics_reporting.mojom", "notification.mojom", "prefs.mojom", + "remoting.mojom", "screen_manager.mojom", "select_file.mojom", "system_display.mojom", @@ -49,6 +50,7 @@ "//mojo/public/mojom/base", "//printing/backend/mojom", "//printing/mojom", + "//remoting/host/mojom:mojom", "//services/device/public/mojom:mojom", "//services/media_session/public/mojom:mojom", "//ui/accessibility:ax_enums_mojo",
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom index a499f39f..1ffb62b 100644 --- a/chromeos/crosapi/mojom/crosapi.mojom +++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -24,6 +24,7 @@ import "chromeos/crosapi/mojom/message_center.mojom"; import "chromeos/crosapi/mojom/metrics_reporting.mojom"; import "chromeos/crosapi/mojom/prefs.mojom"; +import "chromeos/crosapi/mojom/remoting.mojom"; import "chromeos/crosapi/mojom/screen_manager.mojom"; import "chromeos/crosapi/mojom/select_file.mojom"; import "chromeos/crosapi/mojom/system_display.mojom"; @@ -60,8 +61,8 @@ // please note the milestone when you added it, to help us reason about // compatibility between the client applications and older ash-chrome binaries. // -// Next version: 30 -// Next method id: 35 +// Next version: 33 +// Next method id: 38 [Stable, Uuid="8b79c34f-2bf8-4499-979a-b17cac522c1e", RenamedFrom="crosapi.mojom.AshChromeService"] interface Crosapi { @@ -169,6 +170,11 @@ // Added in M89. [MinVersion=11] BindPrefs@16(pending_receiver<Prefs> receiver); + // Binds the Remoting service to allow websites running in Lacros to interact + // with Chrome Remote Desktop functionality available in ash-chrome. + // Added in M93. + [MinVersion=32] BindRemoting@37(pending_receiver<Remoting> receiver); + // Binds the ScreenManager interface for interacting with windows, screens and // displays. // Added in M86.
diff --git a/chromeos/crosapi/mojom/remoting.mojom b/chromeos/crosapi/mojom/remoting.mojom new file mode 100644 index 0000000..b64ae82 --- /dev/null +++ b/chromeos/crosapi/mojom/remoting.mojom
@@ -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. + +module crosapi.mojom; + +import "remoting/host/mojom/remote_support.mojom"; + +// Exposes Chrome Remote Desktop functionality in ash-chrome to callers running +// in lacros-chrome. +// Next version: 1 +// Next method id: 2 +[Stable, Uuid="9865af55-8513-4f06-a785-2cb064963c3b"] +interface Remoting { + // Returns the version and supported features of the CRD host in ash-chrome. + GetSupportHostDetails@0() => (remoting.mojom.SupportHostDetails host_details); + + // Provides a way for a caller in lacros-chrome to request a remote support + // session using the Chrome Remote Desktop host running in ash-chrome. + // The caller in this case is expected to be a built-in native message host + // which is acting on the behalf of the Chrome Remote Desktop website client + // (Website URLs and extension IDs are gated behind allow_lists). + // Note: Starting a new session will disconnect the active session if one + // exists. + StartSupportSession@1(remoting.mojom.SupportSessionParams params) => ( + remoting.mojom.StartSupportSessionResponse response); +}; \ No newline at end of file
diff --git a/chromeos/dbus/shill/fake_modem_messaging_client.cc b/chromeos/dbus/shill/fake_modem_messaging_client.cc index 2327785..531d01b 100644 --- a/chromeos/dbus/shill/fake_modem_messaging_client.cc +++ b/chromeos/dbus/shill/fake_modem_messaging_client.cc
@@ -20,41 +20,47 @@ const std::string& service_name, const dbus::ObjectPath& object_path, const SmsReceivedHandler& handler) { - sms_received_handler_ = handler; + sms_received_handlers_.insert( + std::pair<dbus::ObjectPath, SmsReceivedHandler>(object_path, handler)); + message_paths_map_.insert( + std::pair<dbus::ObjectPath, std::vector<dbus::ObjectPath>>(object_path, + {})); } void FakeModemMessagingClient::ResetSmsReceivedHandler( const std::string& service_name, const dbus::ObjectPath& object_path) { - sms_received_handler_.Reset(); + sms_received_handlers_[object_path].Reset(); } void FakeModemMessagingClient::Delete(const std::string& service_name, const dbus::ObjectPath& object_path, const dbus::ObjectPath& sms_path, VoidDBusMethodCallback callback) { - std::vector<dbus::ObjectPath>::iterator it( - find(message_paths_.begin(), message_paths_.end(), sms_path)); - if (it != message_paths_.end()) - message_paths_.erase(it); + std::vector<dbus::ObjectPath> message_paths = message_paths_map_[object_path]; + auto iter = find(message_paths.begin(), message_paths.end(), sms_path); + if (iter != message_paths.end()) + message_paths.erase(iter); std::move(callback).Run(true); } void FakeModemMessagingClient::List(const std::string& service_name, const dbus::ObjectPath& object_path, ListCallback callback) { - // This entire FakeModemMessagingClient is for testing. - // Calling List with |service_name| equal to "AddSMS" allows unit - // tests to confirm that the sms_received_handler is functioning. - if (service_name == "AddSMS") { - const dbus::ObjectPath kSmsPath("/SMS/0"); - message_paths_.push_back(kSmsPath); - if (!sms_received_handler_.is_null()) - sms_received_handler_.Run(kSmsPath, true); - std::move(callback).Run({}); - } else { - std::move(callback).Run(message_paths_); - } + std::move(callback).Run(message_paths_map_[object_path]); +} + +ModemMessagingClient::TestInterface* +FakeModemMessagingClient::GetTestInterface() { + return this; +} + +// ModemMessagingClient::TestInterface overrides. + +void FakeModemMessagingClient::ReceiveSms(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& sms_path) { + message_paths_map_[object_path].push_back(sms_path); + sms_received_handlers_[object_path].Run(sms_path, true); } } // namespace chromeos
diff --git a/chromeos/dbus/shill/fake_modem_messaging_client.h b/chromeos/dbus/shill/fake_modem_messaging_client.h index 316763c..e3aeebd 100644 --- a/chromeos/dbus/shill/fake_modem_messaging_client.h +++ b/chromeos/dbus/shill/fake_modem_messaging_client.h
@@ -5,6 +5,7 @@ #ifndef CHROMEOS_DBUS_SHILL_FAKE_MODEM_MESSAGING_CLIENT_H_ #define CHROMEOS_DBUS_SHILL_FAKE_MODEM_MESSAGING_CLIENT_H_ +#include <map> #include <string> #include <vector> @@ -16,7 +17,8 @@ namespace chromeos { class COMPONENT_EXPORT(SHILL_CLIENT) FakeModemMessagingClient - : public ModemMessagingClient { + : public ModemMessagingClient, + public ModemMessagingClient::TestInterface { public: FakeModemMessagingClient(); ~FakeModemMessagingClient() override; @@ -34,9 +36,15 @@ const dbus::ObjectPath& object_path, ListCallback callback) override; + ModemMessagingClient::TestInterface* GetTestInterface() override; + + // ModemMessagingClient::TestInterface overrides. + void ReceiveSms(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& sms_path) override; + private: - SmsReceivedHandler sms_received_handler_; - std::vector<dbus::ObjectPath> message_paths_; + std::map<dbus::ObjectPath, SmsReceivedHandler> sms_received_handlers_; + std::map<dbus::ObjectPath, std::vector<dbus::ObjectPath>> message_paths_map_; DISALLOW_COPY_AND_ASSIGN(FakeModemMessagingClient); };
diff --git a/chromeos/dbus/shill/modem_messaging_client.cc b/chromeos/dbus/shill/modem_messaging_client.cc index 972c05bc..7458d12 100644 --- a/chromeos/dbus/shill/modem_messaging_client.cc +++ b/chromeos/dbus/shill/modem_messaging_client.cc
@@ -164,6 +164,8 @@ GetProxy(service_name, object_path)->List(std::move(callback)); } + TestInterface* GetTestInterface() override { return nullptr; } + private: using ProxyMap = std::map<std::pair<std::string, std::string>, std::unique_ptr<ModemMessagingProxy>>;
diff --git a/chromeos/dbus/shill/modem_messaging_client.h b/chromeos/dbus/shill/modem_messaging_client.h index 83e4da78..d3df4a9 100644 --- a/chromeos/dbus/shill/modem_messaging_client.h +++ b/chromeos/dbus/shill/modem_messaging_client.h
@@ -30,6 +30,17 @@ base::RepeatingCallback<void(const dbus::ObjectPath& message_path, bool complete)>; + // Interface for performing modem messaging actions for testing. + // Accessed through GetTestInterface(), only implemented in the Stub Impl. + class TestInterface { + public: + virtual void ReceiveSms(const dbus::ObjectPath& object_path, + const dbus::ObjectPath& sms_path) = 0; + + protected: + virtual ~TestInterface() {} + }; + // Creates and initializes the global instance. |bus| must not be null. static void Initialize(dbus::Bus* bus); @@ -63,6 +74,9 @@ const dbus::ObjectPath& object_path, ListCallback callback) = 0; + // Returns an interface for testing (stub only), or returns null. + virtual TestInterface* GetTestInterface() = 0; + protected: friend class ModemMessagingClientTest;
diff --git a/chromeos/lacros/lacros_chrome_service_impl.cc b/chromeos/lacros/lacros_chrome_service_impl.cc index f40de446..0d7958de 100644 --- a/chromeos/lacros/lacros_chrome_service_impl.cc +++ b/chromeos/lacros/lacros_chrome_service_impl.cc
@@ -32,6 +32,7 @@ #include "chromeos/crosapi/mojom/message_center.mojom.h" #include "chromeos/crosapi/mojom/metrics_reporting.mojom.h" #include "chromeos/crosapi/mojom/prefs.mojom.h" +#include "chromeos/crosapi/mojom/remoting.mojom.h" #include "chromeos/crosapi/mojom/screen_manager.mojom.h" #include "chromeos/crosapi/mojom/select_file.mojom.h" #include "chromeos/crosapi/mojom/system_display.mojom.h" @@ -240,6 +241,9 @@ Crosapi::MethodMinVersions::kBindMessageCenterMinVersion>(); ConstructRemote<crosapi::mojom::Prefs, &crosapi::mojom::Crosapi::BindPrefs, Crosapi::MethodMinVersions::kBindPrefsMinVersion>(); + ConstructRemote<crosapi::mojom::Remoting, + &crosapi::mojom::Crosapi::BindRemoting, + Crosapi::MethodMinVersions::kBindRemotingMinVersion>(); ConstructRemote<crosapi::mojom::SelectFile, &crosapi::mojom::Crosapi::BindSelectFile, Crosapi::MethodMinVersions::kBindSelectFileMinVersion>();
diff --git a/chromeos/network/BUILD.gn b/chromeos/network/BUILD.gn index e05bc18..340b6061b 100644 --- a/chromeos/network/BUILD.gn +++ b/chromeos/network/BUILD.gn
@@ -70,6 +70,8 @@ "firewall_hole.h", "geolocation_handler.cc", "geolocation_handler.h", + "hermes_metrics_util.cc", + "hermes_metrics_util.h", "managed_network_configuration_handler.cc", "managed_network_configuration_handler.h", "managed_network_configuration_handler_impl.cc", @@ -286,6 +288,7 @@ "cellular_metrics_logger_unittest.cc", "certificate_helper_unittest.cc", "client_cert_resolver_unittest.cc", + "device_state_unittest.cc", "fast_transition_observer_unittest.cc", "firewall_hole_unittest.cc", "geolocation_handler_unittest.cc",
diff --git a/chromeos/network/cellular_utils.cc b/chromeos/network/cellular_utils.cc index 4aadeb4..41a07fe 100644 --- a/chromeos/network/cellular_utils.cc +++ b/chromeos/network/cellular_utils.cc
@@ -116,7 +116,7 @@ const base::flat_map<int32_t, std::string> esim_slot_to_eid = GetESimSlotToEidMap(); - DeviceState::CellularSIMSlotInfos sim_slot_infos = device->sim_slot_infos(); + DeviceState::CellularSIMSlotInfos sim_slot_infos = device->GetSimSlotInfos(); for (auto& sim_slot_info : sim_slot_infos) { const std::string shill_provided_eid = sim_slot_info.eid; @@ -140,9 +140,7 @@ } bool IsSimPrimary(const std::string& iccid, const DeviceState* device) { - const DeviceState::CellularSIMSlotInfos& sim_slot_infos = - device->sim_slot_infos(); - for (auto& sim_slot_info : sim_slot_infos) { + for (const auto& sim_slot_info : device->GetSimSlotInfos()) { if (sim_slot_info.iccid == iccid && sim_slot_info.primary) { return true; }
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc index 6572659..2780036 100644 --- a/chromeos/network/client_cert_resolver_unittest.cc +++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -139,6 +139,7 @@ network_profile_handler_.reset(); network_state_handler_.reset(); NetworkCertLoader::Shutdown(); + SystemTokenCertDbStorage::Shutdown(); shill_clients::Shutdown(); }
diff --git a/chromeos/network/device_state.cc b/chromeos/network/device_state.cc index e2c6d797..754bf3b 100644 --- a/chromeos/network/device_state.cc +++ b/chromeos/network/device_state.cc
@@ -153,6 +153,30 @@ return name(); } +DeviceState::CellularSIMSlotInfos DeviceState::GetSimSlotInfos() const { + // If information was provided from Shill, return it directly. + if (!sim_slot_infos_.empty()) + return sim_slot_infos_; + + // Non-cellular types do not have any SIM slots. + if (type() != shill::kTypeCellular) { + NET_LOG(ERROR) << "Attempted to fetch SIM slots for device of type " + << type() << ". Returning empty list."; + return {}; + } + + // Some devices do not return SIMSlotInfo properties (see b/189874098). If the + // list is currently empty, we assume that this is a single-pSIM device and + // return one CellularSIMSlotInfo object representing the single pSIM. + CellularSIMSlotInfo info; + info.slot_id = 1; // Slot numbers start at 1, not 0. + info.eid = std::string(); // Empty EID implies a physical SIM slot. + info.iccid = iccid(); // Copy ICCID property. + info.primary = true; // Only one slot, so it must be the primary one. + + return CellularSIMSlotInfos{info}; +} + std::string DeviceState::GetIpAddressByType(const std::string& type) const { for (base::DictionaryValue::Iterator iter(ip_configs_); !iter.IsAtEnd(); iter.Advance()) {
diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h index 63ea91c..d025331 100644 --- a/chromeos/network/device_state.h +++ b/chromeos/network/device_state.h
@@ -54,7 +54,6 @@ const std::string& iccid() const { return iccid_; } const std::string& mdn() const { return mdn_; } const CellularScanResults& scan_results() const { return scan_results_; } - const CellularSIMSlotInfos& sim_slot_infos() const { return sim_slot_infos_; } bool inhibited() const { return inhibited_; } // |ip_configs_| is kept up to date by NetworkStateHandler. @@ -81,6 +80,9 @@ available_managed_network_path_ = available_managed_network_path; } + // Non-cellular devices return an empty list. + CellularSIMSlotInfos GetSimSlotInfos() const; + // Returns a human readable string for the device. std::string GetName() const;
diff --git a/chromeos/network/device_state_unittest.cc b/chromeos/network/device_state_unittest.cc new file mode 100644 index 0000000..7a01b08 --- /dev/null +++ b/chromeos/network/device_state_unittest.cc
@@ -0,0 +1,119 @@ +// 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 "chromeos/network/device_state.h" + +#include "base/test/task_environment.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_state_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/shill/dbus-constants.h" + +namespace chromeos { +namespace { + +const char kTestCellularDevicePath[] = "cellular_path"; +const char kTestCellularDeviceName[] = "cellular_name"; +const char kTestCellularPSimIccid[] = "psim_iccid"; +const char kTestCellularESimIccid[] = "esim_iccid"; +const char kTestCellularEid[] = "eid"; + +const char kTestWifiDevicePath[] = "wifi_path"; +const char kTestWifiDeviceName[] = "wifi_name"; + +// Creates a list of cellular SIM slots with an eSIM and pSIM slot. +base::Value GenerateTestSimSlotInfos() { + base::Value::ListStorage sim_slot_infos; + + base::Value psim_slot_info(base::Value::Type::DICTIONARY); + psim_slot_info.SetStringKey(shill::kSIMSlotInfoICCID, kTestCellularPSimIccid); + psim_slot_info.SetStringKey(shill::kSIMSlotInfoEID, std::string()); + psim_slot_info.SetBoolKey(shill::kSIMSlotInfoPrimary, true); + sim_slot_infos.push_back(std::move(psim_slot_info)); + + base::Value esim_slot_info(base::Value::Type::DICTIONARY); + psim_slot_info.SetStringKey(shill::kSIMSlotInfoICCID, kTestCellularESimIccid); + psim_slot_info.SetStringKey(shill::kSIMSlotInfoEID, kTestCellularEid); + psim_slot_info.SetBoolKey(shill::kSIMSlotInfoPrimary, false); + sim_slot_infos.push_back(std::move(psim_slot_info)); + + return base::Value(sim_slot_infos); +} + +} // namespace + +class DeviceStateTest : public testing::Test { + protected: + DeviceStateTest() = default; + DeviceStateTest(const DeviceStateTest&) = delete; + DeviceStateTest& operator=(const DeviceStateTest&) = delete; + ~DeviceStateTest() override = default; + + // testing::Test: + void SetUp() override { + helper_.device_test()->AddDevice( + kTestCellularDevicePath, shill::kTypeCellular, kTestCellularDeviceName); + helper_.device_test()->AddDevice(kTestWifiDevicePath, shill::kTypeWifi, + kTestWifiDeviceName); + base::RunLoop().RunUntilIdle(); + } + + const DeviceState* GetCellularDevice() { + return helper_.network_state_handler()->GetDeviceState( + kTestCellularDevicePath); + } + + const DeviceState* GetWifiDevice() { + return helper_.network_state_handler()->GetDeviceState(kTestWifiDevicePath); + } + + void SetIccid() { + helper_.device_test()->SetDeviceProperty( + kTestCellularDevicePath, shill::kIccidProperty, + base::Value(kTestCellularPSimIccid), /*notify_changed=*/true); + base::RunLoop().RunUntilIdle(); + } + + void SetSimSlotInfos() { + helper_.device_test()->SetDeviceProperty( + kTestCellularDevicePath, shill::kSIMSlotInfoProperty, + GenerateTestSimSlotInfos(), /*notify_changed=*/true); + base::RunLoop().RunUntilIdle(); + } + + private: + base::test::SingleThreadTaskEnvironment task_environment_; + NetworkStateTestHelper helper_{/*use_default_devices_and_services=*/false}; +}; + +TEST_F(DeviceStateTest, SimSlotInfo_Cellular) { + // Set an ICCID, but do not set the SIMSlotInfo property. + SetIccid(); + + // A single SIM slot should have been created, copying the ICCID. + DeviceState::CellularSIMSlotInfos infos = + GetCellularDevice()->GetSimSlotInfos(); + EXPECT_EQ(1u, infos.size()); + EXPECT_EQ(kTestCellularPSimIccid, infos[0].iccid); + EXPECT_TRUE(infos[0].eid.empty()); + EXPECT_TRUE(infos[0].primary); + + // Set the SIM Slot infos. + SetSimSlotInfos(); + infos = GetCellularDevice()->GetSimSlotInfos(); + EXPECT_EQ(2u, infos.size()); + EXPECT_EQ(kTestCellularPSimIccid, infos[0].iccid); + EXPECT_TRUE(infos[0].eid.empty()); + EXPECT_TRUE(infos[0].primary); + EXPECT_EQ(kTestCellularESimIccid, infos[1].iccid); + EXPECT_EQ(kTestCellularEid, infos[1].eid); + EXPECT_FALSE(infos[1].primary); +} + +TEST_F(DeviceStateTest, SimSlotInfo_Wifi) { + // Default SIM slots should not be created for non-cellular. + EXPECT_TRUE(GetWifiDevice()->GetSimSlotInfos().empty()); +} + +} // namespace chromeos
diff --git a/chromeos/services/cellular_setup/metrics_util.cc b/chromeos/network/hermes_metrics_util.cc similarity index 78% rename from chromeos/services/cellular_setup/metrics_util.cc rename to chromeos/network/hermes_metrics_util.cc index 38834703..c45bcf6 100644 --- a/chromeos/services/cellular_setup/metrics_util.cc +++ b/chromeos/network/hermes_metrics_util.cc
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromeos/services/cellular_setup/metrics_util.h" +#include "chromeos/network/hermes_metrics_util.h" #include "base/metrics/histogram_functions.h" namespace chromeos { -namespace cellular_setup { -namespace metrics { +namespace hermes_metrics { void LogInstallViaQrCodeResult(HermesResponseStatus status) { base::UmaHistogramEnumeration("Network.Cellular.ESim.InstallViaQrCode.Result", @@ -20,6 +19,5 @@ "Network.Cellular.ESim.InstallPendingProfile.Result", status); } -} // namespace metrics -} // namespace cellular_setup +} // namespace hermes_metrics } // namespace chromeos
diff --git a/chromeos/network/hermes_metrics_util.h b/chromeos/network/hermes_metrics_util.h new file mode 100644 index 0000000..d4e54bc6 --- /dev/null +++ b/chromeos/network/hermes_metrics_util.h
@@ -0,0 +1,23 @@ +// 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 CHROMEOS_NETWORK_HERMES_METRICS_UTIL_H_ +#define CHROMEOS_NETWORK_HERMES_METRICS_UTIL_H_ + +#include "base/component_export.h" +#include "chromeos/dbus/hermes/hermes_response_status.h" + +namespace chromeos { +namespace hermes_metrics { + +void COMPONENT_EXPORT(CHROMEOS_NETWORK) + LogInstallViaQrCodeResult(HermesResponseStatus status); + +void COMPONENT_EXPORT(CHROMEOS_NETWORK) + LogInstallPendingProfileResult(HermesResponseStatus status); + +} // namespace hermes_metrics +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_HERMES_METRICS_UTIL_H_
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc index 6d06848..f947732 100644 --- a/chromeos/network/network_connection_handler_impl.cc +++ b/chromeos/network/network_connection_handler_impl.cc
@@ -550,8 +550,7 @@ const std::string& service_path, base::TimeDelta timeout) { ConnectRequest* request = GetPendingRequest(service_path); - if (!request) - return; + DCHECK(request); request->timer = std::make_unique<base::OneShotTimer>(); request->timer->Start(
diff --git a/chromeos/network/network_sms_handler.cc b/chromeos/network/network_sms_handler.cc index ed2721fe..1d9ac0bd 100644 --- a/chromeos/network/network_sms_handler.cc +++ b/chromeos/network/network_sms_handler.cc
@@ -41,8 +41,6 @@ public: NetworkSmsDeviceHandler() = default; virtual ~NetworkSmsDeviceHandler() = default; - - virtual void RequestUpdate() = 0; }; class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler @@ -52,8 +50,6 @@ const std::string& service_name, const dbus::ObjectPath& object_path); - void RequestUpdate() override; - private: void ListCallback(absl::optional<std::vector<dbus::ObjectPath>> paths); void SmsReceivedCallback(const dbus::ObjectPath& path, bool complete); @@ -101,16 +97,6 @@ weak_ptr_factory_.GetWeakPtr())); } -void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() { - // Calling List using the service "AddSMS" causes the stub - // implementation to deliver new sms messages. - ModemMessagingClient::Get()->List( - std::string("AddSMS"), dbus::ObjectPath("/"), - base::BindOnce(&NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler:: - ListCallback, - weak_ptr_factory_.GetWeakPtr())); -} - void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback( absl::optional<std::vector<dbus::ObjectPath>> paths) { // This receives all messages, so clear any pending gets and deletes. @@ -228,16 +214,10 @@ weak_ptr_factory_.GetWeakPtr())); } -void NetworkSmsHandler::RequestUpdate(bool request_existing) { - // If we already received messages and |request_existing| is true, send - // updates for existing messages. +void NetworkSmsHandler::RequestUpdate() { for (const auto& message : received_messages_) { NotifyMessageReceived(message); } - // Request updates from each device. - for (auto& handler : device_handlers_) { - handler->RequestUpdate(); - } } void NetworkSmsHandler::AddObserver(Observer* observer) {
diff --git a/chromeos/network/network_sms_handler.h b/chromeos/network/network_sms_handler.h index a158f3a..4505302 100644 --- a/chromeos/network/network_sms_handler.h +++ b/chromeos/network/network_sms_handler.h
@@ -43,9 +43,8 @@ ~NetworkSmsHandler() override; - // Requests an immediate check for new messages. If |request_existing| is - // true then also requests to be notified for any already received messages. - void RequestUpdate(bool request_existing); + // Requests an immediate check for new messages. + void RequestUpdate(); void AddObserver(Observer* observer); void RemoveObserver(Observer* observer);
diff --git a/chromeos/network/network_sms_handler_unittest.cc b/chromeos/network/network_sms_handler_unittest.cc index dd8789f3..ecbe032 100644 --- a/chromeos/network/network_sms_handler_unittest.cc +++ b/chromeos/network/network_sms_handler_unittest.cc
@@ -12,8 +12,10 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "chromeos/dbus/constants/dbus_switches.h" +#include "chromeos/dbus/shill/modem_messaging_client.h" #include "chromeos/dbus/shill/shill_clients.h" #include "chromeos/dbus/shill/shill_device_client.h" +#include "dbus/object_path.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -21,6 +23,10 @@ namespace { +const char kCellularDeviceObjectPath[] = + "/org/freedesktop/ModemManager1/stub/0"; +const char kSmsPath[] = "/SMS/0"; + class TestObserver : public NetworkSmsHandler::Observer { public: TestObserver() = default; @@ -65,19 +71,16 @@ ShillDeviceClient::TestInterface* device_test = ShillDeviceClient::Get()->GetTestInterface(); ASSERT_TRUE(device_test); - device_test->AddDevice("/org/freedesktop/ModemManager1/stub/0", - shill::kTypeCellular, + device_test->AddDevice(kCellularDeviceObjectPath, shill::kTypeCellular, "stub_cellular_device2"); // This relies on the stub dbus implementations for ShillManagerClient, // ShillDeviceClient, ModemMessagingClient and SMSClient. - // Initialize a sms handler. The stub dbus clients will not send the - // first test message until RequestUpdate has been called. network_sms_handler_.reset(new NetworkSmsHandler()); network_sms_handler_->Init(); test_observer_ = std::make_unique<TestObserver>(); network_sms_handler_->AddObserver(test_observer_.get()); - network_sms_handler_->RequestUpdate(true); + network_sms_handler_->RequestUpdate(); base::RunLoop().RunUntilIdle(); } @@ -106,7 +109,13 @@ // Test for messages delivered by signals. test_observer_->ClearMessages(); - network_sms_handler_->RequestUpdate(false); + ModemMessagingClient::TestInterface* modem_messaging_test = + ModemMessagingClient::Get()->GetTestInterface(); + modem_messaging_test->ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath), + dbus::ObjectPath(kSmsPath)); + base::RunLoop().RunUntilIdle(); + + network_sms_handler_->RequestUpdate(); base::RunLoop().RunUntilIdle(); EXPECT_GE(test_observer_->message_count(), 1); EXPECT_NE(messages.find(kMessage1), messages.end());
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index 962dcb10..04236d58 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -218,6 +218,18 @@ NotifyNetworkListChanged(); } +void NetworkStateHandler::RequestTrafficCounters( + const std::string& service_path, + ShillServiceClient::ListValueCallback callback) { + shill_property_handler_->RequestTrafficCounters(service_path, + std::move(callback)); +} + +void NetworkStateHandler::ResetTrafficCounters( + const std::string& service_path) { + shill_property_handler_->ResetTrafficCounters(service_path); +} + // static std::unique_ptr<NetworkStateHandler> NetworkStateHandler::InitializeForTest() { auto handler = base::WrapUnique(new NetworkStateHandler());
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h index b67f9162..5f42baf7 100644 --- a/chromeos/network/network_state_handler.h +++ b/chromeos/network/network_state_handler.h
@@ -446,6 +446,13 @@ // set, sorts network list and notifies network list change if required. void SyncStubCellularNetworks(); + // Requests traffic counters for a service denoted by |service_path|. + void RequestTrafficCounters(const std::string& service_path, + ShillServiceClient::ListValueCallback callback); + + // Resets traffic counters for a service denoted by |service_path|. + void ResetTrafficCounters(const std::string& service_path); + bool default_network_is_metered() const { return default_network_is_metered_; }
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc index 6dc432b..34c1b780f 100644 --- a/chromeos/network/network_state_handler_unittest.cc +++ b/chromeos/network/network_state_handler_unittest.cc
@@ -2549,4 +2549,38 @@ EXPECT_EQ(kShillManagerClientStubCellular, network_list[1]->path()); } +TEST_F(NetworkStateHandlerTest, RequestTrafficCounters) { + // Set up the traffic counters. + base::Value traffic_counters(base::Value::Type::LIST); + + base::Value chrome_dict(base::Value::Type::DICTIONARY); + chrome_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceChrome)); + chrome_dict.SetKey("rx_bytes", base::Value(12)); + chrome_dict.SetKey("tx_bytes", base::Value(32)); + traffic_counters.Append(std::move(chrome_dict)); + + base::Value user_dict(base::Value::Type::DICTIONARY); + user_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceUser)); + user_dict.SetKey("rx_bytes", base::Value(90)); + user_dict.SetKey("tx_bytes", base::Value(87)); + traffic_counters.Append(std::move(user_dict)); + + service_test_->SetFakeTrafficCounters(traffic_counters.Clone()); + ASSERT_TRUE(traffic_counters.is_list()); + + base::RunLoop run_loop; + network_state_handler_->RequestTrafficCounters( + kWifiName1, + base::BindOnce( + [](base::Value* expected_traffic_counters, + base::OnceClosure quit_closure, + const base::ListValue& actual_traffic_counters) { + EXPECT_EQ(base::Value::AsListValue(*expected_traffic_counters), + actual_traffic_counters); + std::move(quit_closure).Run(); + }, + &traffic_counters, run_loop.QuitClosure())); + run_loop.Run(); +} + } // namespace chromeos
diff --git a/chromeos/network/stub_cellular_networks_provider.cc b/chromeos/network/stub_cellular_networks_provider.cc index e74288c..cc45864 100644 --- a/chromeos/network/stub_cellular_networks_provider.cc +++ b/chromeos/network/stub_cellular_networks_provider.cc
@@ -134,7 +134,7 @@ // Now, iterate through SIM slots and add metadata for pSIM networks. for (const CellularSIMSlotInfo& sim_slot_info : - cellular_device->sim_slot_infos()) { + cellular_device->GetSimSlotInfos()) { // Skip empty SIM slots. if (sim_slot_info.iccid.empty()) continue;
diff --git a/chromeos/network/system_token_cert_db_storage.cc b/chromeos/network/system_token_cert_db_storage.cc index 3e83a09..1e8e50b 100644 --- a/chromeos/network/system_token_cert_db_storage.cc +++ b/chromeos/network/system_token_cert_db_storage.cc
@@ -4,9 +4,6 @@ #include "chromeos/network/system_token_cert_db_storage.h" -#include <memory> -#include <utility> - #include "base/callback.h" #include "base/callback_list.h" #include "base/check_op.h" @@ -37,16 +34,6 @@ // static void SystemTokenCertDbStorage::Shutdown() { - DCHECK(g_system_token_cert_db_storage); - - // Notify observers that the SystemTokenCertDbStorage and the - // NSSCertDatabase it provides can not be used anymore. - for (auto& observer : g_system_token_cert_db_storage->observers_) - observer.OnSystemTokenCertDbDestroyed(); - - // Now it's safe to destroy the NSSCertDatabase. - g_system_token_cert_db_storage->system_token_cert_database_.reset(); - DCHECK_NE(g_system_token_cert_db_storage, nullptr); delete g_system_token_cert_db_storage; g_system_token_cert_db_storage = nullptr; @@ -58,14 +45,27 @@ } void SystemTokenCertDbStorage::SetDatabase( - std::unique_ptr<net::NSSCertDatabase> system_token_cert_database) { + net::NSSCertDatabase* system_token_cert_database) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(system_token_cert_database_, nullptr); system_token_cert_database_ = std::move(system_token_cert_database); system_token_cert_db_retrieval_timer_.Stop(); - get_system_token_cert_db_callback_list_.Notify( - system_token_cert_database_.get()); + get_system_token_cert_db_callback_list_.Notify(system_token_cert_database_); +} + +void SystemTokenCertDbStorage::ResetDatabase() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + system_token_cert_database_ = nullptr; + // If any consumer asks for the database between now and when + // SystemTokenCertDbStorage is destroyed, respond with a failure. + system_token_cert_db_retrieval_failed_ = true; + + // Notify observers that the SystemTokenCertDbStorage and the + // NSSCertDatabase it provides can not be used anymore. + for (auto& observer : g_system_token_cert_db_storage->observers_) + observer.OnSystemTokenCertDbDestroyed(); } void SystemTokenCertDbStorage::GetDatabase(GetDatabaseCallback callback) { @@ -74,7 +74,7 @@ DCHECK(callback); if (system_token_cert_database_) { - std::move(callback).Run(system_token_cert_database_.get()); + std::move(callback).Run(system_token_cert_database_); } else if (system_token_cert_db_retrieval_failed_) { std::move(callback).Run(/*nss_cert_database=*/nullptr); } else {
diff --git a/chromeos/network/system_token_cert_db_storage.h b/chromeos/network/system_token_cert_db_storage.h index 0bab9371..150243ba 100644 --- a/chromeos/network/system_token_cert_db_storage.h +++ b/chromeos/network/system_token_cert_db_storage.h
@@ -5,8 +5,6 @@ #ifndef CHROMEOS_NETWORK_SYSTEM_TOKEN_CERT_DB_STORAGE_H_ #define CHROMEOS_NETWORK_SYSTEM_TOKEN_CERT_DB_STORAGE_H_ -#include <memory> - #include "base/callback.h" #include "base/callback_forward.h" #include "base/callback_list.h" @@ -66,8 +64,11 @@ // database when it is ready. // Note: This method is expected to be called only once by the // SystemTokenCertDbInitializer. - void SetDatabase( - std::unique_ptr<net::NSSCertDatabase> system_token_cert_database); + void SetDatabase(net::NSSCertDatabase* system_token_cert_database); + + // Used by SystemTokenCertDbInitializer to reset the system token certificate + // database and notify observers that it is not usable anymore. + void ResetDatabase(); // Retrieves the global NSSCertDatabase for the system token and passes it to // |callback|. If the database is already initialized, calls |callback| @@ -89,9 +90,6 @@ // informing callers that the database initialization failed. void OnSystemTokenDbRetrievalTimeout(); - // Global NSSCertDatabase which sees the system token. - std::unique_ptr<net::NSSCertDatabase> system_token_cert_database_; - // List of callbacks that should be executed when the system token certificate // database is created. base::OnceCallbackList<GetDatabaseCallback::RunType> @@ -101,6 +99,10 @@ // NSSCertDatabase is destroyed. base::ObserverList<Observer> observers_; + // Global NSSCertDatabase which sees the system token. Owned by + // SystemTokenCertDbInitializer. + net::NSSCertDatabase* system_token_cert_database_ = nullptr; + bool system_token_cert_db_retrieval_failed_ = false; base::OneShotTimer system_token_cert_db_retrieval_timer_;
diff --git a/chromeos/network/system_token_cert_db_storage_test_util.cc b/chromeos/network/system_token_cert_db_storage_test_util.cc index 7ecde58..50f3d7ab 100644 --- a/chromeos/network/system_token_cert_db_storage_test_util.cc +++ b/chromeos/network/system_token_cert_db_storage_test_util.cc
@@ -47,4 +47,18 @@ run_loop_.Quit(); } +FakeSystemTokenCertDbStorageObserver::FakeSystemTokenCertDbStorageObserver() = + default; + +FakeSystemTokenCertDbStorageObserver::~FakeSystemTokenCertDbStorageObserver() = + default; + +bool FakeSystemTokenCertDbStorageObserver::HasBeenNotified() { + return has_been_notified_; +} + +void FakeSystemTokenCertDbStorageObserver::OnSystemTokenCertDbDestroyed() { + has_been_notified_ = true; +} + } // namespace chromeos
diff --git a/chromeos/network/system_token_cert_db_storage_test_util.h b/chromeos/network/system_token_cert_db_storage_test_util.h index 75c7f9c..fcccae3 100644 --- a/chromeos/network/system_token_cert_db_storage_test_util.h +++ b/chromeos/network/system_token_cert_db_storage_test_util.h
@@ -49,6 +49,26 @@ this}; }; +class FakeSystemTokenCertDbStorageObserver + : public SystemTokenCertDbStorage::Observer { + public: + FakeSystemTokenCertDbStorageObserver(); + FakeSystemTokenCertDbStorageObserver( + const FakeSystemTokenCertDbStorageObserver& other) = delete; + FakeSystemTokenCertDbStorageObserver& operator=( + const FakeSystemTokenCertDbStorageObserver& other) = delete; + ~FakeSystemTokenCertDbStorageObserver() override; + + // Waits until the observer has been notified with . + bool HasBeenNotified(); + + private: + // SystemTokenCertDbStorage::Obsever: + void OnSystemTokenCertDbDestroyed() override; + + bool has_been_notified_ = false; +}; + } // namespace chromeos #endif // CHROMEOS_NETWORK_SYSTEM_TOKEN_CERT_DB_STORAGE_TEST_UTIL_H_
diff --git a/chromeos/network/system_token_cert_db_storage_unittest.cc b/chromeos/network/system_token_cert_db_storage_unittest.cc index c86230b..1c414086 100644 --- a/chromeos/network/system_token_cert_db_storage_unittest.cc +++ b/chromeos/network/system_token_cert_db_storage_unittest.cc
@@ -39,12 +39,12 @@ protected: void SetSystemSlotInStorage() { - auto fake_nss_cert_db = std::make_unique<net::NSSCertDatabase>( + test_cert_database_ = std::make_unique<net::NSSCertDatabase>( /*public_slot=*/crypto::ScopedPK11Slot( PK11_ReferenceSlot(test_nssdb_->slot())), /*private_slot=*/crypto::ScopedPK11Slot( PK11_ReferenceSlot(test_nssdb_->slot()))); - SystemTokenCertDbStorage::Get()->SetDatabase(std::move(fake_nss_cert_db)); + SystemTokenCertDbStorage::Get()->SetDatabase(test_cert_database_.get()); } base::test::TaskEnvironment* task_environment() { return &task_environment_; } @@ -54,6 +54,7 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<crypto::ScopedTestNSSDB> test_nssdb_; + std::unique_ptr<net::NSSCertDatabase> test_cert_database_; }; // Tests that the system token certificate database will be returned @@ -156,4 +157,47 @@ get_system_token_cert_db_callback_wrapper_2.IsDbRetrievalSucceeded()); } +// Tests that calling ResetDatabase notifies the observers. +TEST_F(SystemTokenCertDbStorageTest, ResetDatabaseNotifiesObservers) { + // Successfully request the database. + GetSystemTokenCertDbCallbackWrapper get_system_token_cert_db_callback_wrapper; + SystemTokenCertDbStorage::Get()->GetDatabase( + get_system_token_cert_db_callback_wrapper.GetCallback()); + SetSystemSlotInStorage(); + get_system_token_cert_db_callback_wrapper.Wait(); + EXPECT_TRUE(get_system_token_cert_db_callback_wrapper.IsCallbackCalled()); + + // When the database is reset, observers are notified about this. + FakeSystemTokenCertDbStorageObserver observer; + SystemTokenCertDbStorage::Get()->AddObserver(&observer); + + SystemTokenCertDbStorage::Get()->ResetDatabase(); + + EXPECT_TRUE(observer.HasBeenNotified()); + SystemTokenCertDbStorage::Get()->RemoveObserver(&observer); +} + +// Tests that requesting a database after it has been reset fails. +TEST_F(SystemTokenCertDbStorageTest, RequestingDatabaseFailsAfterReset) { + // Successfully request the database. + GetSystemTokenCertDbCallbackWrapper get_system_token_cert_db_callback_wrapper; + SystemTokenCertDbStorage::Get()->GetDatabase( + get_system_token_cert_db_callback_wrapper.GetCallback()); + SetSystemSlotInStorage(); + get_system_token_cert_db_callback_wrapper.Wait(); + EXPECT_TRUE(get_system_token_cert_db_callback_wrapper.IsCallbackCalled()); + + // Now reset the database. + SystemTokenCertDbStorage::Get()->ResetDatabase(); + + // Requesting the database after that results in a failure. + GetSystemTokenCertDbCallbackWrapper + get_system_token_cert_db_callback_wrapper_2; + SystemTokenCertDbStorage::Get()->GetDatabase( + get_system_token_cert_db_callback_wrapper_2.GetCallback()); + EXPECT_TRUE(get_system_token_cert_db_callback_wrapper_2.IsCallbackCalled()); + EXPECT_FALSE( + get_system_token_cert_db_callback_wrapper_2.IsDbRetrievalSucceeded()); +} + } // namespace chromeos
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt index 0e80bec..3af6988 100644 --- a/chromeos/profiles/orderfile.newest.txt +++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@ -chromeos-chrome-orderfile-field-92-4484.0-1621849150-benchmark-92.0.4515.32-r1.orderfile.xz +chromeos-chrome-orderfile-field-92-4515.9-1622461123-benchmark-92.0.4515.41-r1.orderfile.xz
diff --git a/chromeos/services/assistant/media_host.cc b/chromeos/services/assistant/media_host.cc index c8c91e0..94dea32 100644 --- a/chromeos/services/assistant/media_host.cc +++ b/chromeos/services/assistant/media_host.cc
@@ -283,9 +283,6 @@ } void MediaHost::StartObservingMediaController() { - if (!features::IsMediaSessionIntegrationEnabled()) - return; - if (chromeos_media_state_observer_) return;
diff --git a/chromeos/services/assistant/public/cpp/features.cc b/chromeos/services/assistant/public/cpp/features.cc index 13b2406..0b19075a 100644 --- a/chromeos/services/assistant/public/cpp/features.cc +++ b/chromeos/services/assistant/public/cpp/features.cc
@@ -50,9 +50,6 @@ const base::Feature kEnableLibAssistantBetaBackend{ "LibAssistantBetaBackend", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kEnableMediaSessionIntegration{ - "AssistantEnableMediaSessionIntegration", base::FEATURE_ENABLED_BY_DEFAULT}; - // Disable voice match for test purpose. const base::Feature kDisableVoiceMatch{"DisableVoiceMatch", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -90,10 +87,6 @@ return base::FeatureList::IsEnabled(kAssistantLauncherChipIntegration); } -bool IsMediaSessionIntegrationEnabled() { - return base::FeatureList::IsEnabled(kEnableMediaSessionIntegration); -} - bool IsPowerManagerEnabled() { return base::FeatureList::IsEnabled(kEnablePowerManager); }
diff --git a/chromeos/services/assistant/public/cpp/features.h b/chromeos/services/assistant/public/cpp/features.h index 5955d79..2e9576b 100644 --- a/chromeos/services/assistant/public/cpp/features.h +++ b/chromeos/services/assistant/public/cpp/features.h
@@ -48,10 +48,6 @@ COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) extern const base::Feature kEnableDspHotword; -// Enables MediaSession Integration. -COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) -extern const base::Feature kEnableMediaSessionIntegration; - // Enables stereo audio input. COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) extern const base::Feature kEnableStereoAudioInput; @@ -64,8 +60,6 @@ COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) extern const base::Feature kEnableLibAssistantBetaBackend; -COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAmbientAssistantEnabled(); - COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAppSupportEnabled(); COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAudioEraserEnabled(); @@ -85,17 +79,11 @@ COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsLauncherChipIntegrationEnabled(); -COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) -bool IsMediaSessionIntegrationEnabled(); - COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsPowerManagerEnabled(); COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsLibAssistantBetaBackendEnabled(); -COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) -bool IsResponseProcessingV2Enabled(); - COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsRoutinesEnabled(); COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsStereoAudioInputEnabled();
diff --git a/chromeos/services/cellular_setup/BUILD.gn b/chromeos/services/cellular_setup/BUILD.gn index d9a3fb9f..aa818d9 100644 --- a/chromeos/services/cellular_setup/BUILD.gn +++ b/chromeos/services/cellular_setup/BUILD.gn
@@ -36,8 +36,6 @@ "esim_profile.h", "euicc.cc", "euicc.h", - "metrics_util.cc", - "metrics_util.h", ] deps = [
diff --git a/chromeos/services/cellular_setup/esim_profile.cc b/chromeos/services/cellular_setup/esim_profile.cc index 72aedec..497b54d 100644 --- a/chromeos/services/cellular_setup/esim_profile.cc +++ b/chromeos/services/cellular_setup/esim_profile.cc
@@ -14,6 +14,7 @@ #include "chromeos/network/cellular_esim_profile.h" #include "chromeos/network/cellular_esim_uninstall_handler.h" #include "chromeos/network/cellular_inhibitor.h" +#include "chromeos/network/hermes_metrics_util.h" #include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_handler.h" @@ -21,7 +22,6 @@ #include "chromeos/services/cellular_setup/esim_manager.h" #include "chromeos/services/cellular_setup/esim_mojo_utils.h" #include "chromeos/services/cellular_setup/euicc.h" -#include "chromeos/services/cellular_setup/metrics_util.h" #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom-shared.h" #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" #include "components/device_event_log/device_event_log.h" @@ -388,7 +388,7 @@ void ESimProfile::OnPendingProfileInstallResult( std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, HermesResponseStatus status) { - metrics::LogInstallPendingProfileResult(status); + hermes_metrics::LogInstallPendingProfileResult(status); if (status != HermesResponseStatus::kSuccess) { NET_LOG(ERROR) << "Error Installing pending profile status="
diff --git a/chromeos/services/cellular_setup/euicc.cc b/chromeos/services/cellular_setup/euicc.cc index d0eefef1..b65fd7d 100644 --- a/chromeos/services/cellular_setup/euicc.cc +++ b/chromeos/services/cellular_setup/euicc.cc
@@ -13,13 +13,13 @@ #include "chromeos/network/cellular_connection_handler.h" #include "chromeos/network/cellular_esim_profile.h" #include "chromeos/network/cellular_inhibitor.h" +#include "chromeos/network/hermes_metrics_util.h" #include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/services/cellular_setup/esim_manager.h" #include "chromeos/services/cellular_setup/esim_mojo_utils.h" #include "chromeos/services/cellular_setup/esim_profile.h" -#include "chromeos/services/cellular_setup/metrics_util.h" #include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom-shared.h" #include "components/device_event_log/device_event_log.h" #include "components/qr_code_generator/qr_code_generator.h" @@ -260,7 +260,7 @@ std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock, HermesResponseStatus status, const dbus::ObjectPath* profile_path) { - metrics::LogInstallViaQrCodeResult(status); + hermes_metrics::LogInstallViaQrCodeResult(status); if (status != HermesResponseStatus::kSuccess) { NET_LOG(ERROR) << "Error Installing profile status="
diff --git a/chromeos/services/cellular_setup/metrics_util.h b/chromeos/services/cellular_setup/metrics_util.h deleted file mode 100644 index 1a9a1e4..0000000 --- a/chromeos/services/cellular_setup/metrics_util.h +++ /dev/null
@@ -1,21 +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 CHROMEOS_SERVICES_CELLULAR_SETUP_METRICS_UTIL_H_ -#define CHROMEOS_SERVICES_CELLULAR_SETUP_METRICS_UTIL_H_ - -#include "chromeos/dbus/hermes/hermes_response_status.h" - -namespace chromeos { -namespace cellular_setup { -namespace metrics { - -void LogInstallViaQrCodeResult(HermesResponseStatus status); -void LogInstallPendingProfileResult(HermesResponseStatus status); - -} // namespace metrics -} // namespace cellular_setup -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_CELLULAR_SETUP_METRICS_UTIL_H_
diff --git a/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc b/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc index cabc4f4..4f5bf0a 100644 --- a/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc +++ b/chromeos/services/cellular_setup/ota_activator_impl_unittest.cc
@@ -103,10 +103,11 @@ device_test->SetDeviceProperty( kTestCellularDevicePath, shill::kMdnProperty, base::Value(kTestCellularDeviceMdn), false /* notify_changed */); - } else if (has_physical_slots) { + } else { + std::string eid = has_physical_slots ? std::string() : "test_eid"; device_test->SetDeviceProperty( kTestCellularDevicePath, shill::kSIMSlotInfoProperty, - CreateCellularSIMSlotInfo(kTestCellularServiceIccid), + CreateCellularSIMSlotInfo(kTestCellularServiceIccid, eid), false /* notify_changed */); } @@ -254,10 +255,12 @@ is_finished_ = true; } - base::Value CreateCellularSIMSlotInfo(const std::string& iccid) { + base::Value CreateCellularSIMSlotInfo( + const std::string& iccid, + const std::string& eid = std::string()) { base::Value::ListStorage sim_slot_infos; base::Value slot_info_item(base::Value::Type::DICTIONARY); - slot_info_item.SetStringKey(shill::kSIMSlotInfoEID, std::string()); + slot_info_item.SetStringKey(shill::kSIMSlotInfoEID, eid); slot_info_item.SetStringKey(shill::kSIMSlotInfoICCID, iccid); slot_info_item.SetBoolKey(shill::kSIMSlotInfoPrimary, false); sim_slot_infos.push_back(std::move(slot_info_item));
diff --git a/chromeos/services/libassistant/display_connection_impl.cc b/chromeos/services/libassistant/display_connection_impl.cc index 2cbeffe1..7474d42 100644 --- a/chromeos/services/libassistant/display_connection_impl.cc +++ b/chromeos/services/libassistant/display_connection_impl.cc
@@ -15,11 +15,9 @@ DisplayConnectionImpl::DisplayConnectionImpl( DisplayConnectionObserver* observer, - bool feedback_ui_enabled, - bool media_session_enabled) + bool feedback_ui_enabled) : observer_(observer), feedback_ui_enabled_(feedback_ui_enabled), - media_session_enabled_(media_session_enabled), task_runner_(base::SequencedTaskRunnerHandle::Get()) { DCHECK(observer_); } @@ -136,14 +134,12 @@ } } - if (media_session_enabled_) { - set_capabilities_request->mutable_supported_features() - ->set_media_session_detection( - related_info_enabled_ - ? ::assistant::api::RELIABLE_MEDIA_SESSION_DETECTION - : ::assistant::api:: - MEDIA_SESSION_DETECTION_DISABLED_SCREEN_CONTEXT); - } + set_capabilities_request->mutable_supported_features() + ->set_media_session_detection( + related_info_enabled_ + ? ::assistant::api::RELIABLE_MEDIA_SESSION_DETECTION + : ::assistant::api:: + MEDIA_SESSION_DETECTION_DISABLED_SCREEN_CONTEXT); } } // namespace libassistant
diff --git a/chromeos/services/libassistant/display_connection_impl.h b/chromeos/services/libassistant/display_connection_impl.h index 53095f9..387ba99 100644 --- a/chromeos/services/libassistant/display_connection_impl.h +++ b/chromeos/services/libassistant/display_connection_impl.h
@@ -27,8 +27,7 @@ class DisplayConnectionImpl : public assistant_client::DisplayConnection { public: DisplayConnectionImpl(DisplayConnectionObserver* observer, - bool feedback_ui_enabled, - bool media_session_enabled); + bool feedback_ui_enabled); DisplayConnectionImpl(const DisplayConnectionImpl&) = delete; DisplayConnectionImpl& operator=(const DisplayConnectionImpl&) = delete; ~DisplayConnectionImpl() override; @@ -60,9 +59,6 @@ // Whether Assistant feedback UI is enabled. const bool feedback_ui_enabled_; - // Whether Media Session support is enabled. - const bool media_session_enabled_; - // Whether ARC++ is enabled. bool arc_play_store_enabled_ GUARDED_BY(update_display_request_mutex_) = false;
diff --git a/chromeos/services/libassistant/display_controller.cc b/chromeos/services/libassistant/display_controller.cc index 6f8e959..5509e60b 100644 --- a/chromeos/services/libassistant/display_controller.cc +++ b/chromeos/services/libassistant/display_controller.cc
@@ -50,8 +50,7 @@ : event_observer_(std::make_unique<EventObserver>(this)), display_connection_(std::make_unique<DisplayConnectionImpl>( event_observer_.get(), - /*feedback_ui_enabled=*/true, - assistant::features::IsMediaSessionIntegrationEnabled())), + /*feedback_ui_enabled=*/true)), speech_recognition_observers_(*speech_recognition_observers), mojom_task_runner_(base::SequencedTaskRunnerHandle::Get()) { DCHECK(speech_recognition_observers);
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc index 9ae3bb3..9c725d3ec 100644 --- a/chromeos/services/network_config/cros_network_config.cc +++ b/chromeos/services/network_config/cros_network_config.cc
@@ -4,6 +4,7 @@ #include "chromeos/services/network_config/cros_network_config.h" +#include <cmath> #include <vector> #include "ash/constants/ash_features.h" @@ -433,14 +434,36 @@ return sim_info_mojos; } -mojom::InhibitReason GetInhibitReason(CellularInhibitor* cellular_inhibitor) { +bool IsCellularConnecting(NetworkStateHandler* network_state_handler) { + NetworkStateHandler::NetworkStateList cellular_networks; + network_state_handler->GetVisibleNetworkListByType( + NetworkTypePattern::Cellular(), &cellular_networks); + auto iter = std::find_if(cellular_networks.begin(), cellular_networks.end(), + [](const NetworkState* network_state) { + return network_state->IsConnectingState(); + }); + return iter != cellular_networks.end(); +} + +mojom::InhibitReason GetInhibitReason( + NetworkStateHandler* network_state_handler, + CellularInhibitor* cellular_inhibitor) { if (!cellular_inhibitor) return mojom::InhibitReason::kNotInhibited; absl::optional<CellularInhibitor::InhibitReason> inhibit_reason = cellular_inhibitor->GetInhibitReason(); - if (!inhibit_reason) + if (!inhibit_reason) { + // For devices with EUICC, the UI should be inhibited when a cellular + // network connection is in progress to prevent additional requests. This is + // due to complexity in switching slots. + if (!chromeos::HermesManagerClient::Get()->GetAvailableEuiccs().empty() && + IsCellularConnecting(network_state_handler)) { + return mojom::InhibitReason::kConnectingToProfile; + } + return mojom::InhibitReason::kNotInhibited; + } switch (*inhibit_reason) { case CellularInhibitor::InhibitReason::kInstallingProfile: @@ -458,6 +481,7 @@ mojom::DeviceStatePropertiesPtr DeviceStateToMojo( const DeviceState* device, + NetworkStateHandler* network_state_handler, CellularInhibitor* cellular_inhibitor, mojom::DeviceStateType technology_state) { mojom::NetworkType type = ShillTypeToMojo(device->type()); @@ -503,7 +527,8 @@ } if (type == mojom::NetworkType::kCellular) { result->sim_infos = CellularSIMInfosToMojo(device); - result->inhibit_reason = GetInhibitReason(cellular_inhibitor); + result->inhibit_reason = + GetInhibitReason(network_state_handler, cellular_inhibitor); } return result; } @@ -1819,6 +1844,30 @@ return result; } +mojom::TrafficCounterSource ConvertToTrafficCounterSourceEnum( + const std::string& source) { + if (source == shill::kTrafficCounterSourceUnknown) + return mojom::TrafficCounterSource::kUnknown; + if (source == shill::kTrafficCounterSourceChrome) + return mojom::TrafficCounterSource::kChrome; + if (source == shill::kTrafficCounterSourceUser) + return mojom::TrafficCounterSource::kUser; + if (source == shill::kTrafficCounterSourceArc) + return mojom::TrafficCounterSource::kArc; + if (source == shill::kTrafficCounterSourceCrosvm) + return mojom::TrafficCounterSource::kCrosvm; + if (source == shill::kTrafficCounterSourcePluginvm) + return mojom::TrafficCounterSource::kPluginvm; + if (source == shill::kTrafficCounterSourceUpdateEngine) + return mojom::TrafficCounterSource::kUpdateEngine; + if (source == shill::kTrafficCounterSourceVpn) + return mojom::TrafficCounterSource::kVpn; + if (source == shill::kTrafficCounterSourceSystem) + return mojom::TrafficCounterSource::kSystem; + NOTREACHED() << "Unknown traffic counter source: " << source; + return mojom::TrafficCounterSource::kUnknown; +} + } // namespace CrosNetworkConfig::CrosNetworkConfig() @@ -1958,8 +2007,8 @@ NET_LOG(ERROR) << "Device state unavailable: " << device->name(); continue; } - mojom::DeviceStatePropertiesPtr mojo_device = - DeviceStateToMojo(device, cellular_inhibitor_, technology_state); + mojom::DeviceStatePropertiesPtr mojo_device = DeviceStateToMojo( + device, network_state_handler_, cellular_inhibitor_, technology_state); if (mojo_device) result.emplace_back(std::move(mojo_device)); } @@ -2799,6 +2848,77 @@ network_profile_handler_->SetAlwaysOnVpnService(profile->path, service_path); } +void CrosNetworkConfig::RequestTrafficCounters( + const std::string& guid, + RequestTrafficCountersCallback callback) { + std::string service_path = GetServicePathFromGuid(guid); + if (service_path.empty()) { + NET_LOG(ERROR) << "RequestTrafficCounters: service path for guid " << guid + << " not found"; + std::move(callback).Run({}); + return; + } + network_state_handler_->RequestTrafficCounters( + service_path, + base::BindOnce(&CrosNetworkConfig::PopulateTrafficCounters, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +// static +mojom::TrafficCounterSource CrosNetworkConfig::GetTrafficCounterEnumForTesting( + const std::string& source) { + return ConvertToTrafficCounterSourceEnum(source); +} + +void CrosNetworkConfig::PopulateTrafficCounters( + RequestTrafficCountersCallback callback, + const base::ListValue& traffic_counters) { + if (!traffic_counters.GetList().size()) { + std::move(callback).Run({}); + return; + } + std::vector<mojom::TrafficCounterPtr> counters; + for (const base::Value& tc : traffic_counters.GetList()) { + DCHECK(tc.is_dict()); + const base::Value* source = + tc.FindKeyOfType("source", base::Value::Type::STRING); + DCHECK(source); + + // Since rx_bytes may be larger than the maximum value representable by + // uint32_t, we must check whether it was implicitly converted to a double + // during D-Bus deserialization. + uint64_t rx_bytes; + const base::Value* rb = tc.FindKey("rx_bytes"); + DCHECK(rb); + if (rb->type() == base::Value::Type::INTEGER) { + rx_bytes = rb->GetInt(); + } else if (rb->type() == base::Value::Type::DOUBLE) { + rx_bytes = std::floor(rb->GetDouble()); + } else { + NOTREACHED(); + } + + // Since tx_bytes may be larger than the maximum value representable by + // uint32_t, we must check whether it was implicitly converted to a double + // during D-Bus deserialization. + uint64_t tx_bytes; + const base::Value* tb = tc.FindKey("tx_bytes"); + DCHECK(tb); + if (tb->type() == base::Value::Type::INTEGER) { + tx_bytes = tb->GetInt(); + } else if (tb->type() == base::Value::Type::DOUBLE) { + tx_bytes = std::floor(tb->GetDouble()); + } else { + NOTREACHED(); + } + + counters.push_back(mojom::TrafficCounter::New( + ConvertToTrafficCounterSourceEnum(source->GetString()), rx_bytes, + tx_bytes)); + } + std::move(callback).Run(std::move(counters)); +} + // NetworkStateHandlerObserver void CrosNetworkConfig::NetworkListChanged() { for (auto& observer : observers_) @@ -2848,6 +2968,17 @@ DeviceListChanged(); } +void CrosNetworkConfig::NetworkConnectionStateChanged( + const NetworkState* network) { + if (!network->Matches(NetworkTypePattern::Cellular())) { + return; + } + // inhibit_reason device property is dependent on network connection state of + // cellular networks. Notify device list change so that clients will update + // with new inhibit reason. + DeviceListChanged(); +} + void CrosNetworkConfig::OnShuttingDown() { if (network_state_handler_->HasObserver(this)) network_state_handler_->RemoveObserver(this, FROM_HERE);
diff --git a/chromeos/services/network_config/cros_network_config.h b/chromeos/services/network_config/cros_network_config.h index cdc3e548..aa26a0c 100644 --- a/chromeos/services/network_config/cros_network_config.h +++ b/chromeos/services/network_config/cros_network_config.h
@@ -94,6 +94,12 @@ void GetNetworkCertificates(GetNetworkCertificatesCallback callback) override; void GetAlwaysOnVpn(GetAlwaysOnVpnCallback callback) override; void SetAlwaysOnVpn(mojom::AlwaysOnVpnPropertiesPtr properties) override; + void RequestTrafficCounters(const std::string& guid, + RequestTrafficCountersCallback callback) override; + + // static + static mojom::TrafficCounterSource GetTrafficCounterEnumForTesting( + const std::string& source); private: void OnGetManagedProperties(GetManagedPropertiesCallback callback, @@ -153,6 +159,8 @@ void OnGetAlwaysOnVpn(GetAlwaysOnVpnCallback callback, std::string mode, std::string service_path); + void PopulateTrafficCounters(RequestTrafficCountersCallback callback, + const base::ListValue& traffic_counters); // NetworkStateHandlerObserver: void NetworkListChanged() override; @@ -164,6 +172,7 @@ void OnShuttingDown() override; void ScanStarted(const DeviceState* device) override; void ScanCompleted(const DeviceState* device) override; + void NetworkConnectionStateChanged(const NetworkState* network) override; // NetworkCertificateHandler::Observer void OnCertificatesChanged() override;
diff --git a/chromeos/services/network_config/cros_network_config_unittest.cc b/chromeos/services/network_config/cros_network_config_unittest.cc index acc1de0..6c5afb4 100644 --- a/chromeos/services/network_config/cros_network_config_unittest.cc +++ b/chromeos/services/network_config/cros_network_config_unittest.cc
@@ -76,6 +76,37 @@ const char kCellularTestApnPassword3[] = "Test Pass"; const char kCellularTestApnAttach3[] = "attach"; +enum ComparisonType { + INTEGER = 0, + DOUBLE, +}; + +void CompareTrafficCounters( + const std::vector<mojom::TrafficCounterPtr>& actual_traffic_counters, + const base::Value* expected_traffic_counters, + enum ComparisonType comparison_type) { + EXPECT_EQ(actual_traffic_counters.size(), + expected_traffic_counters->GetList().size()); + for (size_t i = 0; i < actual_traffic_counters.size(); i++) { + auto& actual_tc = actual_traffic_counters[i]; + auto& expected_tc = expected_traffic_counters->GetList()[i]; + EXPECT_EQ(actual_tc->source, + CrosNetworkConfig::GetTrafficCounterEnumForTesting( + expected_tc.FindKey("source")->GetString())); + if (comparison_type == ComparisonType::INTEGER) { + EXPECT_EQ(actual_tc->rx_bytes, + (size_t)expected_tc.FindKey("rx_bytes")->GetInt()); + EXPECT_EQ(actual_tc->tx_bytes, + (size_t)expected_tc.FindKey("tx_bytes")->GetInt()); + } else if (comparison_type == ComparisonType::DOUBLE) { + EXPECT_EQ(actual_tc->rx_bytes, + (size_t)expected_tc.FindKey("rx_bytes")->GetDouble()); + EXPECT_EQ(actual_tc->tx_bytes, + (size_t)expected_tc.FindKey("tx_bytes")->GetDouble()); + } + } +} + } // namespace class CrosNetworkConfigTest : public testing::Test { @@ -582,6 +613,25 @@ return inhibit_lock; } + void RequestTrafficCountersAndCompareTrafficCounters( + const std::string& guid, + base::Value traffic_counters, + ComparisonType comparison_type) { + base::RunLoop run_loop; + cros_network_config()->RequestTrafficCounters( + guid, + base::BindOnce( + [](base::Value* expected_traffic_counters, ComparisonType* type, + base::OnceClosure quit_closure, + std::vector<mojom::TrafficCounterPtr> actual_traffic_counters) { + CompareTrafficCounters(actual_traffic_counters, + expected_traffic_counters, *type); + std::move(quit_closure).Run(); + }, + &traffic_counters, &comparison_type, run_loop.QuitClosure())); + run_loop.Run(); + } + NetworkHandlerTestHelper* helper() { return helper_.get(); } CrosNetworkConfigTestObserver* observer() { return observer_.get(); } CrosNetworkConfig* cros_network_config() { @@ -1344,6 +1394,39 @@ EXPECT_EQ(mojom::InhibitReason::kInstallingProfile, cellular->inhibit_reason); } +TEST_F(CrosNetworkConfigTest, CellularInhibitState_Connecting) { + const char kTestEuiccPath[] = "euicc_path"; + mojom::DeviceStatePropertiesPtr cellular = + GetDeviceStateFromList(mojom::NetworkType::kCellular); + ASSERT_TRUE(cellular); + EXPECT_EQ(mojom::DeviceStateType::kEnabled, cellular->device_state); + EXPECT_EQ(mojom::InhibitReason::kNotInhibited, cellular->inhibit_reason); + + // Set connect requested on cellular network. + NetworkStateHandler* network_state_handler = + NetworkHandler::Get()->network_state_handler(); + const NetworkState* network_state = + network_state_handler->GetNetworkStateFromGuid("cellular_guid"); + network_state_handler->SetNetworkConnectRequested(network_state->path(), + true); + + // Verify the inhibit state is not set when connecting if there are no EUICC. + cellular = GetDeviceStateFromList(mojom::NetworkType::kCellular); + ASSERT_TRUE(cellular); + EXPECT_EQ(mojom::DeviceStateType::kEnabled, cellular->device_state); + EXPECT_EQ(mojom::InhibitReason::kNotInhibited, cellular->inhibit_reason); + + // Verify the adding EUICC sets the inhibit reason correctly. + helper()->hermes_manager_test()->AddEuicc(dbus::ObjectPath(kTestEuiccPath), + "eid", /*is_active=*/true, + /*physical_slot=*/0); + cellular = GetDeviceStateFromList(mojom::NetworkType::kCellular); + ASSERT_TRUE(cellular); + EXPECT_EQ(mojom::DeviceStateType::kEnabled, cellular->device_state); + EXPECT_EQ(mojom::InhibitReason::kConnectingToProfile, + cellular->inhibit_reason); +} + TEST_F(CrosNetworkConfigTest, SetCellularSimState) { // Assert initial state. mojom::DeviceStatePropertiesPtr cellular = @@ -1633,10 +1716,12 @@ SetupObserver(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(0, observer()->device_state_list_changed()); + NetworkStateHandler* network_state_handler = + NetworkHandler::Get()->network_state_handler(); // Disable wifi - NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled( - NetworkTypePattern::WiFi(), false, network_handler::ErrorCallback()); + network_state_handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), false, + network_handler::ErrorCallback()); base::RunLoop().RunUntilIdle(); // This will trigger three device list updates. First when wifi is in the // disabling state, next when it's actually disabled, and lastly when @@ -1644,22 +1729,31 @@ EXPECT_EQ(3, observer()->device_state_list_changed()); // Enable Tethering - NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState( + network_state_handler->SetTetherTechnologyState( NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); base::RunLoop().RunUntilIdle(); EXPECT_EQ(4, observer()->device_state_list_changed()); // Tests that observers are notified of device state list change // when a tether scan begins for a device. - NetworkHandler::Get()->network_state_handler()->SetTetherScanState(true); + network_state_handler->SetTetherScanState(true); base::RunLoop().RunUntilIdle(); EXPECT_EQ(5, observer()->device_state_list_changed()); // Tests that observers are notified of device state list change // when a tether scan completes. - NetworkHandler::Get()->network_state_handler()->SetTetherScanState(false); + network_state_handler->SetTetherScanState(false); base::RunLoop().RunUntilIdle(); EXPECT_EQ(6, observer()->device_state_list_changed()); + + // Test that observers are notified of device state list change + // when a cellular network connection state changes. + const NetworkState* network_state = + network_state_handler->GetNetworkStateFromGuid("cellular_guid"); + network_state_handler->SetNetworkConnectRequested(network_state->path(), + /*connect_requested=*/true); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(7, observer()->device_state_list_changed()); } TEST_F(CrosNetworkConfigTest, ActiveNetworksChanged) { @@ -1806,5 +1900,51 @@ shill::kAlwaysOnVpnServiceProperty)); } +TEST_F(CrosNetworkConfigTest, RequestTrafficCountersWithIntegerType) { + base::Value traffic_counters(base::Value::Type::LIST); + + base::Value chrome_dict(base::Value::Type::DICTIONARY); + chrome_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceChrome)); + chrome_dict.SetKey("rx_bytes", base::Value(12)); + chrome_dict.SetKey("tx_bytes", base::Value(32)); + traffic_counters.Append(std::move(chrome_dict)); + + base::Value user_dict(base::Value::Type::DICTIONARY); + user_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceUser)); + user_dict.SetKey("rx_bytes", base::Value(90)); + user_dict.SetKey("tx_bytes", base::Value(87)); + traffic_counters.Append(std::move(user_dict)); + + ASSERT_TRUE(traffic_counters.is_list()); + ASSERT_EQ(traffic_counters.GetList().size(), (size_t)2); + helper()->service_test()->SetFakeTrafficCounters(traffic_counters.Clone()); + + RequestTrafficCountersAndCompareTrafficCounters( + "wifi1_guid", traffic_counters.Clone(), ComparisonType::INTEGER); +} + +TEST_F(CrosNetworkConfigTest, RequestTrafficCountersWithDoubleType) { + base::Value traffic_counters(base::Value::Type::LIST); + + base::Value chrome_dict(base::Value::Type::DICTIONARY); + chrome_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceChrome)); + chrome_dict.SetKey("rx_bytes", base::Value(123456789987.0)); + chrome_dict.SetKey("tx_bytes", base::Value(3211234567898.0)); + traffic_counters.Append(std::move(chrome_dict)); + + base::Value user_dict(base::Value::Type::DICTIONARY); + user_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceUser)); + user_dict.SetKey("rx_bytes", base::Value(9000000000000000.0)); + user_dict.SetKey("tx_bytes", base::Value(8765432112345.0)); + traffic_counters.Append(std::move(user_dict)); + + ASSERT_TRUE(traffic_counters.is_list()); + ASSERT_EQ(traffic_counters.GetList().size(), (size_t)2); + helper()->service_test()->SetFakeTrafficCounters(traffic_counters.Clone()); + + RequestTrafficCountersAndCompareTrafficCounters( + "wifi1_guid", traffic_counters.Clone(), ComparisonType::DOUBLE); +} + } // namespace network_config } // namespace chromeos
diff --git a/chromeos/services/network_config/public/mojom/cros_network_config.mojom b/chromeos/services/network_config/public/mojom/cros_network_config.mojom index 676e0d5..acbf310 100644 --- a/chromeos/services/network_config/public/mojom/cros_network_config.mojom +++ b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
@@ -907,6 +907,32 @@ string service_guid; }; +// Source of the traffic. These sources are kept in sync with +// third_party/cros_system_api/dbus/shill/dbus-constants.h. +enum TrafficCounterSource { + kUnknown, + kChrome, + kUser, + kArc, + kCrosvm, + kPluginvm, + kUpdateEngine, + kVpn, + kSystem, +}; + +// Information about a traffic counter for a single source. +struct TrafficCounter { + // Source of traffic. + TrafficCounterSource source; + // Corresponds to the number of bytes received by |source| since the last + // reset. + uint64 rx_bytes; + // Corresponds to the number of bytes transmitted by |source| since the last + // reset. + uint64 tx_bytes; +}; + // Interface for fetching and setting network configuration properties, e.g. // from Settings WebUI or the SystemTray. interface CrosNetworkConfig { @@ -1023,6 +1049,10 @@ // Sets the always-on VPN mode and service with |properties.mode| and // |properties.service_guid|. The service GUID must match a VPN service. SetAlwaysOnVpn(AlwaysOnVpnProperties properties); + + // Requests traffic counters for a service with ID |guid|. + RequestTrafficCounters(string guid) => + (array<TrafficCounter> traffic_counters); }; interface CrosNetworkConfigObserver {
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 1b537c07..5ba2235 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -958,7 +958,8 @@ void AutofillAgent::FormControlElementClicked( const WebFormControlElement& element, bool was_focused) { - last_clicked_form_control_element_for_testing_ = element; + last_clicked_form_control_element_for_testing_ = + FieldRendererId(element.UniqueRendererFormControlId()); last_clicked_form_control_element_was_focused_for_testing_ = was_focused; was_last_action_fill_ = false; @@ -1158,7 +1159,7 @@ void AutofillAgent::ResetLastInteractedElements() { last_interacted_form_.Reset(); - last_clicked_form_control_element_for_testing_.Reset(); + last_clicked_form_control_element_for_testing_ = {}; formless_elements_user_edited_.clear(); provisionally_saved_form_.reset(); }
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index 7276726..a3a96731 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -354,7 +354,7 @@ bool focused_node_was_last_clicked_ = false; bool was_focused_before_now_ = false; - blink::WebFormControlElement last_clicked_form_control_element_for_testing_; + FieldRendererId last_clicked_form_control_element_for_testing_; bool last_clicked_form_control_element_was_focused_for_testing_ = false; FormTracker form_tracker_;
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc index f8df0f64..ebfc20e 100644 --- a/components/autofill/core/browser/autofill_suggestion_generator.cc +++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -241,7 +241,6 @@ // TODO(crbug.com/1196021): Populate custom_icon with card art if available. suggestion.frontend_id = POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY; - suggestion.is_value_secondary = true; } return suggestion;
diff --git a/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/components/autofill/core/browser/data_model/autofill_structured_address_component.h index b97444f..ec0b659e 100644 --- a/components/autofill/core/browser/data_model/autofill_structured_address_component.h +++ b/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -26,6 +26,7 @@ // Represents the validation status of value stored in the AutofillProfile. // The associated integer values used to store the verification code in SQL and // should not be modified. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.autofill enum class VerificationStatus { // No verification status assigned. kNoStatus = 0,
diff --git a/components/breadcrumbs/core/breadcrumb_manager.cc b/components/breadcrumbs/core/breadcrumb_manager.cc index 6a6f7ea..0d97455 100644 --- a/components/breadcrumbs/core/breadcrumb_manager.cc +++ b/components/breadcrumbs/core/breadcrumb_manager.cc
@@ -24,7 +24,7 @@ const int kMinEventsBuckets = 2; // Returns a Time used to bucket events for easier discarding of expired events. -base::Time EventBucket(const base::Time& time) { +base::Time GetBucketTime(const base::Time& time) { base::Time::Exploded exploded; time.LocalExplode(&exploded); exploded.millisecond = 0; @@ -47,8 +47,7 @@ size_t count = 0; for (auto it = event_buckets_.rbegin(); it != event_buckets_.rend(); ++it) { - std::list<std::string> bucket_events = it->second; - count += bucket_events.size(); + count += it->events.size(); } return count; } @@ -59,10 +58,10 @@ std::list<std::string> events; for (auto it = event_buckets_.rbegin(); it != event_buckets_.rend(); ++it) { - std::list<std::string> bucket_events = it->second; + const std::list<std::string>& bucket_events = it->events; for (auto event_it = bucket_events.rbegin(); event_it != bucket_events.rend(); ++event_it) { - std::string event = *event_it; + const std::string& event = *event_it; events.push_front(event); if (event_count_limit > 0 && events.size() >= event_count_limit) { return events; @@ -74,13 +73,11 @@ void BreadcrumbManager::AddEvent(const std::string& event) { base::Time time = base::Time::Now(); - base::Time bucket_time = EventBucket(time); + base::Time bucket_time = GetBucketTime(time); - // If bucket exists, it will be at the end of the list. - if (event_buckets_.empty() || event_buckets_.back().first != bucket_time) { - std::pair<base::Time, std::list<std::string>> bucket( - bucket_time, std::list<std::string>()); - event_buckets_.push_back(bucket); + // If a bucket exists, it will be at the end of the list. + if (event_buckets_.empty() || event_buckets_.back().time != bucket_time) { + event_buckets_.emplace_back(bucket_time); } base::Time::Exploded exploded; @@ -89,7 +86,7 @@ base::StringPrintf("%02d:%02d", exploded.minute, exploded.second); std::string event_log = base::StringPrintf("%s %s", timestamp.c_str(), event.c_str()); - event_buckets_.back().second.push_back(event_log); + event_buckets_.back().events.push_back(event_log); for (auto& observer : observers_) { observer.EventAdded(this, event_log); @@ -106,7 +103,7 @@ base::Time now = base::Time::Now(); // Drop buckets which are more than kMessageExpirationTime old. while (event_buckets_.size() > kMinEventsBuckets) { - base::Time oldest_bucket_time = event_buckets_.front().first; + base::Time oldest_bucket_time = event_buckets_.front().time; if (now - oldest_bucket_time < kMessageExpirationTime) { break; } @@ -118,7 +115,7 @@ unsigned long newer_event_count = 0; auto event_bucket_it = event_buckets_.rbegin(); while (event_bucket_it != event_buckets_.rend()) { - std::list<std::string> bucket_events = event_bucket_it->second; + std::list<std::string> bucket_events = event_bucket_it->events; if (newer_event_count > kMaxUsefulBreadcrumbEvents) { event_buckets_.erase(event_buckets_.begin(), event_bucket_it.base()); old_buckets_dropped = true; @@ -143,4 +140,9 @@ observers_.RemoveObserver(observer); } +BreadcrumbManager::EventBucket::EventBucket(base::Time bucket_time) + : time(bucket_time) {} +BreadcrumbManager::EventBucket::EventBucket(const EventBucket&) = default; +BreadcrumbManager::EventBucket::~EventBucket() = default; + } // namespace breadcrumbs
diff --git a/components/breadcrumbs/core/breadcrumb_manager.h b/components/breadcrumbs/core/breadcrumb_manager.h index 22bec33..1c162e8b 100644 --- a/components/breadcrumbs/core/breadcrumb_manager.h +++ b/components/breadcrumbs/core/breadcrumb_manager.h
@@ -59,9 +59,17 @@ // Creation time of the BreadcrumbManager. const base::Time start_time_; - // List of events, paired with the time which they were logged to minute - // resolution. Newer events are at the end of the list. - std::list<std::pair<base::Time, std::list<std::string>>> event_buckets_; + // List of events, paired with the time they were logged to minute resolution. + // Newer events are at the end of the list. + struct EventBucket { + base::Time time; + std::list<std::string> events; + + explicit EventBucket(base::Time bucket_time); + EventBucket(const EventBucket&); + ~EventBucket(); + }; + std::list<EventBucket> event_buckets_; base::ObserverList<BreadcrumbManagerObserver, /*check_empty=*/true> observers_;
diff --git a/components/cronet/android/sample/AndroidManifest.xml b/components/cronet/android/sample/AndroidManifest.xml index 26d99b0..64b7e06 100644 --- a/components/cronet/android/sample/AndroidManifest.xml +++ b/components/cronet/android/sample/AndroidManifest.xml
@@ -7,6 +7,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" package="org.chromium.cronet_sample_apk"> <uses-permission android:name="android.permission.INTERNET"/> @@ -23,5 +24,12 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + <!-- Disables at startup init of Emoji2. See http://crbug.com/1205141 --> + <provider + android:authorities="org.chromium.cronet_sample_apk.androidx-startup" + android:name="androidx.startup.InitializationProvider" + android:exported="false" + tools:node="remove"> + </provider> </application> </manifest>
diff --git a/components/feedback/redaction_tool.cc b/components/feedback/redaction_tool.cc index deaad29..06d82ad 100644 --- a/components/feedback/redaction_tool.cc +++ b/components/feedback/redaction_tool.cc
@@ -726,6 +726,7 @@ re2::StringPiece text(input); re2::StringPiece skipped; re2::StringPiece matched_id; + const re2::StringPiece dash("-"); while (FindAndConsumeAndGetSkipped(&text, *re, &skipped, &matched_id)) { if (IsUrlExempt(matched_id, first_party_extension_ids_)) { skipped.AppendToString(&result); @@ -737,6 +738,14 @@ if (identifier_space->count(matched_id_as_string) == 0) { replacement_id = MaybeScrubIPAddress(matched_id_as_string); if (replacement_id != matched_id_as_string) { + // USB paths can be confused with IPv4 Addresses because they can look + // similar: n-n.n.n.n . Ignore replacement if previous char is `-` + if (skipped.ends_with(dash) && strcmp("IPv4", pattern.alias) == 0) { + skipped.AppendToString(&result); + matched_id.AppendToString(&result); + continue; + } + // The weird NumberToString trick is because Windows does not like // to deal with %zu and a size_t in printf, nor does it support %llu. replacement_id = base::StringPrintf(
diff --git a/components/feedback/redaction_tool_unittest.cc b/components/feedback/redaction_tool_unittest.cc index 594de525..10f06bb 100644 --- a/components/feedback/redaction_tool_unittest.cc +++ b/components/feedback/redaction_tool_unittest.cc
@@ -216,8 +216,18 @@ EXPECT_EQ("[<IPv6: 4>]", RedactCustomPatterns("[aa::bb]")); EXPECT_EQ("State::Abort", RedactCustomPatterns("State::Abort")); + // Real IPv4 address EXPECT_EQ("<IPv4: 1>", RedactCustomPatterns("192.160.0.1")); + // Non-PII IPv4 address (see MaybeScrubIPAddress) + EXPECT_EQ("255.255.255.255", RedactCustomPatterns("255.255.255.255")); + + // Not an actual IPv4 address + EXPECT_EQ("75.748.86.91", RedactCustomPatterns("75.748.86.91")); + + // USB Path - not an actual IPv4 Address + EXPECT_EQ("4-3.3.3.3", RedactCustomPatterns("4-3.3.3.3")); + EXPECT_EQ("<URL: 1>", RedactCustomPatterns("http://example.com/foo?test=1")); EXPECT_EQ("Foo <URL: 2> Bar", RedactCustomPatterns("Foo http://192.168.0.1/foo?test=1#123 Bar")); @@ -368,6 +378,8 @@ "255.255.259.255"}, {"255.300.255.255", // Not an IP address. "255.300.255.255"}, + {"3-1.2.3.4", // USB path, not an IP address. + "3-1.2.3.4"}, {"aaaa123.123.45.4aaa", // IP address. "aaaa<IPv4: 23>aaa"}, {"11:11;11::11", // IP address.
diff --git a/components/gcm_driver/crypto/p256_key_util.cc b/components/gcm_driver/crypto/p256_key_util.cc index 9026682..5954d20 100644 --- a/components/gcm_driver/crypto/p256_key_util.cc +++ b/components/gcm_driver/crypto/p256_key_util.cc
@@ -21,9 +21,6 @@ namespace { -// The first byte in an uncompressed P-256 point per SEC1 2.3.3. -const char kUncompressedPointForm = 0x04; - // A P-256 field element consists of 32 bytes. const size_t kFieldBytes = 32; @@ -38,17 +35,14 @@ std::string candidate_public_key; // ECPrivateKey::ExportRawPublicKey() returns the EC point in the uncompressed - // point format, but does not include the leading byte of value 0x04 that - // indicates usage of uncompressed points, per SEC1 2.3.3. + // point format. if (!key.ExportRawPublicKey(&candidate_public_key) || - candidate_public_key.size() != 2 * kFieldBytes) { + candidate_public_key.size() != kUncompressedPointBytes) { DLOG(ERROR) << "Unable to export the public key."; return false; } - // Concatenate the leading 0x04 byte and the two uncompressed points. public_key->erase(); public_key->reserve(kUncompressedPointBytes); - public_key->push_back(kUncompressedPointForm); public_key->append(candidate_public_key); return true; } @@ -79,11 +73,10 @@ bssl::UniquePtr<EC_POINT> point( EC_POINT_new(EC_KEY_get0_group(ec_private_key))); - if (!point || - !EC_POINT_oct2point( - EC_KEY_get0_group(ec_private_key), point.get(), - reinterpret_cast<const uint8_t*>(peer_public_key.data()), - peer_public_key.size(), nullptr)) { + if (!point || !EC_POINT_oct2point( + EC_KEY_get0_group(ec_private_key), point.get(), + reinterpret_cast<const uint8_t*>(peer_public_key.data()), + peer_public_key.size(), nullptr)) { DLOG(ERROR) << "Can't convert peer public value to curve point."; return false; }
diff --git a/components/live_caption/BUILD.gn b/components/live_caption/BUILD.gn index 0cfc6b44..0766c46e 100644 --- a/components/live_caption/BUILD.gn +++ b/components/live_caption/BUILD.gn
@@ -2,7 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -if (!is_android) { +import("//build/config/ui.gni") + +if (toolkit_views) { static_library("live_caption") { sources = [ "views/caption_bubble.cc", @@ -24,7 +26,7 @@ "//ui/views", ] } -} # !is_android +} # toolkit_views source_set("constants") { sources = [
diff --git a/components/lookalikes/core/lookalike_url_ui_util.cc b/components/lookalikes/core/lookalike_url_ui_util.cc index 5907d14..c507738 100644 --- a/components/lookalikes/core/lookalike_url_ui_util.cc +++ b/components/lookalikes/core/lookalike_url_ui_util.cc
@@ -41,19 +41,18 @@ } } -void PopulateLookalikeUrlBlockingPageStrings( - base::DictionaryValue* load_time_data, - const GURL& safe_url, - const GURL& request_url) { +void PopulateLookalikeUrlBlockingPageStrings(base::Value* load_time_data, + const GURL& safe_url, + const GURL& request_url) { CHECK(load_time_data); PopulateStringsForSharedHTML(load_time_data); - load_time_data->SetString("tabTitle", - l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_TITLE)); - load_time_data->SetString( + load_time_data->SetStringKey( + "tabTitle", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_TITLE)); + load_time_data->SetStringKey( "optInLink", l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE)); - load_time_data->SetString( + load_time_data->SetStringKey( "enhancedProtectionMessage", l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_ENHANCED_PROTECTION_MESSAGE)); @@ -61,60 +60,60 @@ const std::u16string hostname = security_interstitials::common_string_util::GetFormattedHostName( safe_url); - load_time_data->SetString( + load_time_data->SetStringKey( "heading", l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_HEADING, hostname)); - load_time_data->SetString( + load_time_data->SetStringKey( "primaryParagraph", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH)); - load_time_data->SetString( + load_time_data->SetStringKey( "proceedButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_IGNORE)); - load_time_data->SetString( + load_time_data->SetStringKey( "primaryButtonText", l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_CONTINUE, hostname)); } else { // No safe URL available to suggest. This can happen when the navigated // domain fails IDN spoof checks but isn't a lookalike of a known domain. // TODO: Change to actual strings. - load_time_data->SetString( + load_time_data->SetStringKey( "heading", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_HEADING_NO_SUGGESTED_URL)); - load_time_data->SetString( + load_time_data->SetStringKey( "primaryParagraph", l10n_util::GetStringUTF16( IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_NO_SUGGESTED_URL)); - load_time_data->SetString( + load_time_data->SetStringKey( "proceedButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_IGNORE)); - load_time_data->SetString( + load_time_data->SetStringKey( "primaryButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_BACK_TO_SAFETY)); #if defined(OS_IOS) // On iOS, offer to close the page instead of navigating to NTP when the // safe URL is empty or invalid, and unable to go back. - bool show_close_page = false; - load_time_data->GetBoolean("cant_go_back", &show_close_page); - if (show_close_page) { - load_time_data->SetString( + absl::optional<bool> maybe_cant_go_back = + load_time_data->FindBoolKey("cant_go_back"); + if (maybe_cant_go_back && *maybe_cant_go_back) { + load_time_data->SetStringKey( "primaryButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_CLOSE_PAGE)); } #endif } - load_time_data->SetString("lookalikeRequestHostname", request_url.host()); + load_time_data->SetStringKey("lookalikeRequestHostname", request_url.host()); } -void PopulateStringsForSharedHTML(base::DictionaryValue* load_time_data) { - load_time_data->SetBoolean("lookalike_url", true); - load_time_data->SetBoolean("overridable", false); - load_time_data->SetBoolean("hide_primary_button", false); - load_time_data->SetBoolean("show_recurrent_error_paragraph", false); +void PopulateStringsForSharedHTML(base::Value* load_time_data) { + load_time_data->SetBoolKey("lookalike_url", true); + load_time_data->SetBoolKey("overridable", false); + load_time_data->SetBoolKey("hide_primary_button", false); + load_time_data->SetBoolKey("show_recurrent_error_paragraph", false); - load_time_data->SetString("recurrentErrorParagraph", ""); - load_time_data->SetString("openDetails", ""); - load_time_data->SetString("explanationParagraph", ""); - load_time_data->SetString("finalParagraph", ""); + load_time_data->SetStringKey("recurrentErrorParagraph", ""); + load_time_data->SetStringKey("openDetails", ""); + load_time_data->SetStringKey("explanationParagraph", ""); + load_time_data->SetStringKey("finalParagraph", ""); - load_time_data->SetString("type", "LOOKALIKE"); + load_time_data->SetStringKey("type", "LOOKALIKE"); }
diff --git a/components/lookalikes/core/lookalike_url_ui_util.h b/components/lookalikes/core/lookalike_url_ui_util.h index 81e2e08..61cb9bc 100644 --- a/components/lookalikes/core/lookalike_url_ui_util.h +++ b/components/lookalikes/core/lookalike_url_ui_util.h
@@ -9,7 +9,7 @@ #include "services/metrics/public/cpp/ukm_source_id.h" namespace base { -class DictionaryValue; +class Value; } // namespace base // Allow easier reporting of UKM when no interstitial is shown. @@ -27,12 +27,11 @@ bool triggered_by_initial_url); // Populates |load_time_data| for interstitial HTML. -void PopulateLookalikeUrlBlockingPageStrings( - base::DictionaryValue* load_time_data, - const GURL& safe_url, - const GURL& request_url); +void PopulateLookalikeUrlBlockingPageStrings(base::Value* load_time_data, + const GURL& safe_url, + const GURL& request_url); // Values added to get shared interstitial HTML to play nice. -void PopulateStringsForSharedHTML(base::DictionaryValue* load_time_data); +void PopulateStringsForSharedHTML(base::Value* load_time_data); #endif // COMPONENTS_LOOKALIKES_CORE_LOOKALIKE_URL_UI_UTIL_H_
diff --git a/components/metrics/log_store.h b/components/metrics/log_store.h index d624f4a..cb0f633 100644 --- a/components/metrics/log_store.h +++ b/components/metrics/log_store.h
@@ -7,6 +7,8 @@ #include <string> +#include "third_party/abseil-cpp/absl/types/optional.h" + namespace metrics { // Interface for local storage of serialized logs to be reported. @@ -33,6 +35,12 @@ // Will trigger a DCHECK if there is no staged log. virtual const std::string& staged_log_signature() const = 0; + // User id associated with the staged log. Empty if the log was + // recorded during no particular user session or during guest session. + // + // Will trigger a DCHECK if there is no staged log. + virtual absl::optional<uint64_t> staged_log_user_id() const = 0; + // Populates staged_log() with the next stored log to send. // The order in which logs are staged is up to the implementor. // The staged_log must remain the same even if additional logs are added.
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index 384f849..5259f59 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -51,6 +51,23 @@ namespace metrics { +LogMetadata::LogMetadata() + : samples_count(absl::nullopt), user_id(absl::nullopt) {} +LogMetadata::LogMetadata( + const absl::optional<base::HistogramBase::Count> samples_count, + const absl::optional<uint64_t> user_id) + : samples_count(samples_count), user_id(user_id) {} +LogMetadata::LogMetadata(const LogMetadata& other) = default; +LogMetadata::~LogMetadata() = default; + +void LogMetadata::AddSampleCount(base::HistogramBase::Count sample_count) { + if (samples_count.has_value()) { + samples_count = samples_count.value() + sample_count; + } else { + samples_count = sample_count; + } +} + namespace { // A simple class to write histogram data to a log. @@ -134,8 +151,7 @@ RecordCoreSystemProfile(client_, system_profile); } -MetricsLog::~MetricsLog() { -} +MetricsLog::~MetricsLog() = default; // static void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) { @@ -270,7 +286,7 @@ void MetricsLog::RecordHistogramDelta(const std::string& histogram_name, const base::HistogramSamples& snapshot) { DCHECK(!closed_); - samples_count_ += snapshot.TotalCount(); + log_metadata_.AddSampleCount(snapshot.TotalCount()); EncodeHistogramDelta(histogram_name, snapshot, &uma_proto_); }
diff --git a/components/metrics/metrics_log.h b/components/metrics/metrics_log.h index 4043e92..ffbe252 100644 --- a/components/metrics/metrics_log.h +++ b/components/metrics/metrics_log.h
@@ -20,6 +20,7 @@ #include "base/strings/string_piece_forward.h" #include "base/time/time.h" #include "components/metrics/metrics_reporting_default_state.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" #include "third_party/metrics_proto/system_profile.pb.h" @@ -33,6 +34,25 @@ namespace metrics { +// Holds optional metadata associated with a log to be stored. +struct LogMetadata { + LogMetadata(); + LogMetadata(absl::optional<base::HistogramBase::Count> samples_count, + absl::optional<uint64_t> user_id); + LogMetadata(const LogMetadata& other); + ~LogMetadata(); + + // Adds |sample_count| to |samples_count|. If |samples_count| is empty, then + // |sample_count| will populate |samples_count|. + void AddSampleCount(base::HistogramBase::Count sample_count); + + // The total number of samples in this log if applicable. + absl::optional<base::HistogramBase::Count> samples_count; + + // User id associated with the log. + absl::optional<uint64_t> user_id; +}; + class MetricsProvider; class MetricsServiceClient; class DelegatingProvider; @@ -170,9 +190,7 @@ LogType log_type() const { return log_type_; } - // Returns the number of samples in this log, it is only valid after the - // histogram delta is calculated. - base::HistogramBase::Count samples_count() const { return samples_count_; } + const LogMetadata& log_metadata() const { return log_metadata_; } // Exposed for the sake of mocking/accessing in test code. ChromeUserMetricsExtension* UmaProtoForTest() { return &uma_proto_; } @@ -219,8 +237,8 @@ // RecordEnvironment() or LoadSavedEnvironmentFromPrefs(). bool has_environment_; - // The number of samples in this log. - base::HistogramBase::Count samples_count_ = 0; + // Optional metadata associated with the log. + LogMetadata log_metadata_; DISALLOW_COPY_AND_ASSIGN(MetricsLog); };
diff --git a/components/metrics/metrics_log_manager.cc b/components/metrics/metrics_log_manager.cc index 072ea3e..998fd81 100644 --- a/components/metrics/metrics_log_manager.cc +++ b/components/metrics/metrics_log_manager.cc
@@ -30,7 +30,7 @@ current_log_->GetEncodedLog(&log_data); if (!log_data.empty()) { log_store->StoreLog(log_data, current_log_->log_type(), - absl::make_optional(current_log_->samples_count())); + current_log_->log_metadata()); } current_log_.reset(); }
diff --git a/components/metrics/metrics_log_store.cc b/components/metrics/metrics_log_store.cc index 8dfbddf..99b9f6b 100644 --- a/components/metrics/metrics_log_store.cc +++ b/components/metrics/metrics_log_store.cc
@@ -48,17 +48,16 @@ unsent_logs_loaded_ = true; } -void MetricsLogStore::StoreLog( - const std::string& log_data, - MetricsLog::LogType log_type, - absl::optional<base::HistogramBase::Count> samples_count) { +void MetricsLogStore::StoreLog(const std::string& log_data, + MetricsLog::LogType log_type, + const LogMetadata& log_metadata) { switch (log_type) { case MetricsLog::INITIAL_STABILITY_LOG: - initial_log_queue_.StoreLog(log_data, samples_count); + initial_log_queue_.StoreLog(log_data, log_metadata); break; case MetricsLog::ONGOING_LOG: case MetricsLog::INDEPENDENT_LOG: - ongoing_log_queue_.StoreLog(log_data, samples_count); + ongoing_log_queue_.StoreLog(log_data, log_metadata); break; } } @@ -90,6 +89,12 @@ : ongoing_log_queue_.staged_log_signature(); } +absl::optional<uint64_t> MetricsLogStore::staged_log_user_id() const { + // MetricsLogStore base class should never have any logs associated with a + // user ID. + return absl::nullopt; +} + void MetricsLogStore::StageNextLog() { DCHECK(!has_staged_log()); if (initial_log_queue_.has_unsent_logs())
diff --git a/components/metrics/metrics_log_store.h b/components/metrics/metrics_log_store.h index 14f1552..f17590f 100644 --- a/components/metrics/metrics_log_store.h +++ b/components/metrics/metrics_log_store.h
@@ -64,7 +64,7 @@ // Saves |log_data| as the given type. void StoreLog(const std::string& log_data, MetricsLog::LogType log_type, - absl::optional<base::HistogramBase::Count> samples_count); + const LogMetadata& log_metadata); // LogStore: bool has_unsent_logs() const override; @@ -72,6 +72,7 @@ const std::string& staged_log() const override; const std::string& staged_log_hash() const override; const std::string& staged_log_signature() const override; + absl::optional<uint64_t> staged_log_user_id() const override; void StageNextLog() override; void DiscardStagedLog() override; void MarkStagedLogAsSent() override;
diff --git a/components/metrics/metrics_log_store_unittest.cc b/components/metrics/metrics_log_store_unittest.cc index da9ee76..71647cf 100644 --- a/components/metrics/metrics_log_store_unittest.cc +++ b/components/metrics/metrics_log_store_unittest.cc
@@ -50,7 +50,7 @@ EXPECT_FALSE(log_store.has_staged_log()); EXPECT_FALSE(log_store.has_unsent_logs()); - log_store.StoreLog("a", MetricsLog::ONGOING_LOG, absl::nullopt); + log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); EXPECT_TRUE(log_store.has_unsent_logs()); EXPECT_FALSE(log_store.has_staged_log()); @@ -71,7 +71,7 @@ std::string()); log_store.LoadPersistedUnsentLogs(); EXPECT_FALSE(log_store.has_unsent_logs()); - log_store.StoreLog("a", MetricsLog::ONGOING_LOG, absl::nullopt); + log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); log_store.TrimAndPersistUnsentLogs(); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG)); @@ -85,9 +85,9 @@ EXPECT_TRUE(log_store.has_unsent_logs()); EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG)); EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG)); - log_store.StoreLog("x", MetricsLog::INITIAL_STABILITY_LOG, absl::nullopt); + log_store.StoreLog("x", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata()); log_store.StageNextLog(); - log_store.StoreLog("b", MetricsLog::ONGOING_LOG, absl::nullopt); + log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata()); EXPECT_TRUE(log_store.has_unsent_logs()); EXPECT_TRUE(log_store.has_staged_log()); @@ -139,7 +139,7 @@ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(), std::string()); log_store.LoadPersistedUnsentLogs(); - log_store.StoreLog("a", MetricsLog::ONGOING_LOG, absl::nullopt); + log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); log_store.StageNextLog(); log_store.TrimAndPersistUnsentLogs(); @@ -152,7 +152,7 @@ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(), std::string()); log_store.LoadPersistedUnsentLogs(); - log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG, absl::nullopt); + log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata()); log_store.StageNextLog(); log_store.TrimAndPersistUnsentLogs(); @@ -168,8 +168,8 @@ log_store.LoadPersistedUnsentLogs(); log_store.StoreLog("persisted", MetricsLog::INITIAL_STABILITY_LOG, - absl::nullopt); - log_store.StoreLog("not_persisted", MetricsLog::ONGOING_LOG, absl::nullopt); + LogMetadata()); + log_store.StoreLog("not_persisted", MetricsLog::ONGOING_LOG, LogMetadata()); // Only the stability log should be written out, due to the threshold. log_store.TrimAndPersistUnsentLogs(); @@ -184,10 +184,10 @@ std::string()); log_store.LoadPersistedUnsentLogs(); - log_store.StoreLog("a", MetricsLog::ONGOING_LOG, absl::nullopt); - log_store.StoreLog("b", MetricsLog::ONGOING_LOG, absl::nullopt); + log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata()); + log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata()); log_store.StageNextLog(); - log_store.StoreLog("c", MetricsLog::INITIAL_STABILITY_LOG, absl::nullopt); + log_store.StoreLog("c", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata()); EXPECT_EQ(2U, log_store.ongoing_log_count()); EXPECT_EQ(1U, log_store.initial_log_count()); // Should discard the ongoing log staged earlier.
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc index 0393b81..5ade3a8d 100644 --- a/components/metrics/metrics_log_unittest.cc +++ b/components/metrics/metrics_log_unittest.cc
@@ -292,6 +292,29 @@ EXPECT_EQ(12, histogram_proto.bucket(4).max()); } +TEST_F(MetricsLogTest, HistogramSamplesCount) { + const std::string histogram_name = "test"; + TestMetricsServiceClient client; + TestingPrefServiceSimple prefs; + TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client); + + // Create buckets: 1-5. + base::BucketRanges ranges(2); + ranges.set_range(0, 1); + ranges.set_range(1, 5); + + // Add two samples. + base::SampleVector samples(1, &ranges); + samples.Accumulate(3, 2); + log.RecordHistogramDelta(histogram_name, samples); + + EXPECT_EQ(2, log.log_metadata().samples_count.value()); + + // Add two more samples. + log.RecordHistogramDelta(histogram_name, samples); + EXPECT_EQ(4, log.log_metadata().samples_count.value()); +} + TEST_F(MetricsLogTest, RecordEnvironment) { TestMetricsServiceClient client; TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client);
diff --git a/components/metrics/metrics_service_client.cc b/components/metrics/metrics_service_client.cc index 5054743..ba12046 100644 --- a/components/metrics/metrics_service_client.cc +++ b/components/metrics/metrics_service_client.cc
@@ -64,8 +64,7 @@ return nullptr; } -bool MetricsServiceClient::ShouldUploadMetricsForUserId( - const uint64_t user_id) { +bool MetricsServiceClient::ShouldUploadMetricsForUserId(uint64_t user_id) { return true; }
diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h index 277cbd69..5655fa2 100644 --- a/components/metrics/metrics_service_client.h +++ b/components/metrics/metrics_service_client.h
@@ -49,7 +49,7 @@ // Returns true if metrics should be uploaded for the given |user_id|, which // corresponds to the |user_id| field in ChromeUserMetricsExtension. - virtual bool ShouldUploadMetricsForUserId(const uint64_t user_id); + virtual bool ShouldUploadMetricsForUserId(uint64_t user_id); // Registers the client id with other services (e.g. crash reporting), called // when metrics recording gets enabled.
diff --git a/components/metrics/metrics_service_unittest.cc b/components/metrics/metrics_service_unittest.cc index 5d84be0..a61a1fce 100644 --- a/components/metrics/metrics_service_unittest.cc +++ b/components/metrics/metrics_service_unittest.cc
@@ -528,7 +528,7 @@ // is never deserialized to proto, so we're just passing some dummy content. ASSERT_EQ(0u, test_log_store->initial_log_count()); ASSERT_EQ(0u, test_log_store->ongoing_log_count()); - test_log_store->StoreLog("blah_blah", MetricsLog::ONGOING_LOG, absl::nullopt); + test_log_store->StoreLog("blah_blah", MetricsLog::ONGOING_LOG, LogMetadata()); // Note: |initial_log_count()| refers to initial stability logs, so the above // log is counted an ongoing log (per its type). ASSERT_EQ(0u, test_log_store->initial_log_count());
diff --git a/components/metrics/reporting_service.cc b/components/metrics/reporting_service.cc index bfbdbe8..e46d164 100644 --- a/components/metrics/reporting_service.cc +++ b/components/metrics/reporting_service.cc
@@ -6,6 +6,7 @@ #include "components/metrics/reporting_service.h" +#include <cstdio> #include <memory> #include "base/base64.h" @@ -116,6 +117,25 @@ log_store()->StageNextLog(); } + // Check whether the log should be uploaded based on user id. If it should not + // be sent, then discard the log from the store and notify the scheduler. + auto staged_user_id = log_store()->staged_log_user_id(); + if (staged_user_id.has_value() && + !client_->ShouldUploadMetricsForUserId(staged_user_id.value())) { + // Remove the log and update list to disk. + log_store()->DiscardStagedLog(); + log_store()->TrimAndPersistUnsentLogs(); + + // Notify the scheduler that the next log should be uploaded. If there are + // no more logs, then stop the scheduler. + if (!log_store()->has_unsent_logs()) { + DVLOG(1) << "Stopping upload_scheduler_."; + upload_scheduler_->Stop(); + } + upload_scheduler_->UploadFinished(true); + return; + } + // Proceed to stage the log for upload if log size satisfies cellular log // upload constrains. bool upload_canceled = false;
diff --git a/components/metrics/reporting_service_unittest.cc b/components/metrics/reporting_service_unittest.cc index b48b7b9..47f2ec6 100644 --- a/components/metrics/reporting_service_unittest.cc +++ b/components/metrics/reporting_service_unittest.cc
@@ -26,6 +26,18 @@ namespace { +// Represent a flushed log and its metadata to be used for testing. +struct TestLog { + explicit TestLog(const std::string& log) : log(log), user_id(absl::nullopt) {} + TestLog(const std::string& log, uint64_t user_id) + : log(log), user_id(user_id) {} + TestLog(const TestLog& other) = default; + ~TestLog() = default; + + const std::string log; + const absl::optional<uint64_t> user_id; +}; + const char kTestUploadUrl[] = "test_url"; const char kTestMimeType[] = "test_mime_type"; @@ -34,21 +46,25 @@ TestLogStore() {} ~TestLogStore() {} - void AddLog(const std::string& log) { logs_.push_back(log); } + void AddLog(const TestLog& log) { logs_.push_back(log); } // LogStore: bool has_unsent_logs() const override { return !logs_.empty(); } bool has_staged_log() const override { return !staged_log_hash_.empty(); } - const std::string& staged_log() const override { return logs_.front(); } + const std::string& staged_log() const override { return logs_.front().log; } const std::string& staged_log_hash() const override { return staged_log_hash_; } + absl::optional<uint64_t> staged_log_user_id() const override { + return logs_.front().user_id; + } const std::string& staged_log_signature() const override { return base::EmptyString(); } void StageNextLog() override { - if (has_unsent_logs()) - staged_log_hash_ = base::SHA1HashString(logs_.front()); + if (has_unsent_logs()) { + staged_log_hash_ = base::SHA1HashString(logs_.front().log); + } } void DiscardStagedLog() override { if (!has_staged_log()) @@ -62,7 +78,7 @@ private: std::string staged_log_hash_; - std::deque<std::string> logs_; + std::deque<TestLog> logs_; }; class TestReportingService : public ReportingService { @@ -73,7 +89,7 @@ } ~TestReportingService() override {} - void AddLog(const std::string& log) { log_store_.AddLog(log); } + void AddLog(const TestLog& log) { log_store_.AddLog(log); } private: // ReportingService: @@ -117,8 +133,8 @@ TEST_F(ReportingServiceTest, BasicTest) { TestReportingService service(&client_, GetLocalState()); - service.AddLog("log1"); - service.AddLog("log2"); + service.AddLog(TestLog("log1")); + service.AddLog(TestLog("log2")); service.EnableReporting(); task_runner_->RunPendingTasks(); @@ -144,4 +160,41 @@ EXPECT_FALSE(client_.uploader()->is_uploading()); } +TEST_F(ReportingServiceTest, UserIdLogsUploadedIfUserConsented) { + uint64_t user_id = 12345; + + TestReportingService service(&client_, GetLocalState()); + service.AddLog(TestLog("log1", user_id)); + service.AddLog(TestLog("log2", user_id)); + service.EnableReporting(); + client_.AllowMetricUploadForUserId(user_id); + + task_runner_->RunPendingTasks(); + EXPECT_TRUE(client_.uploader()->is_uploading()); + EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count()); + EXPECT_FALSE(client_.uploader()->reporting_info().has_last_response_code()); + client_.uploader()->CompleteUpload(200); + + // Upload 2nd log and last response code logged. + task_runner_->RunPendingTasks(); + EXPECT_EQ(200, client_.uploader()->reporting_info().last_response_code()); + EXPECT_TRUE(client_.uploader()->is_uploading()); + + client_.uploader()->CompleteUpload(200); + EXPECT_EQ(0U, task_runner_->NumPendingTasks()); + EXPECT_FALSE(client_.uploader()->is_uploading()); +} + +TEST_F(ReportingServiceTest, UserIdLogsNotUploadedIfUserNotConsented) { + TestReportingService service(&client_, GetLocalState()); + service.AddLog(TestLog("log1", 12345)); + service.AddLog(TestLog("log2", 12345)); + service.EnableReporting(); + + // Log with user id should never be in uploading state if user upload + // disabled. |client_.uploader()| should be nullptr since it is lazily + // created when a log is to be uploaded for the first time. + EXPECT_EQ(client_.uploader(), nullptr); +} + } // namespace metrics
diff --git a/components/metrics/test/test_metrics_service_client.cc b/components/metrics/test/test_metrics_service_client.cc index 2be627da..5e515255 100644 --- a/components/metrics/test/test_metrics_service_client.cc +++ b/components/metrics/test/test_metrics_service_client.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/callback.h" +#include "base/containers/contains.h" #include "components/metrics/metrics_log_uploader.h" #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" @@ -33,6 +34,10 @@ client_id_ = client_id; } +bool TestMetricsServiceClient::ShouldUploadMetricsForUserId(uint64_t user_id) { + return base::Contains(allowed_user_ids_, user_id); +} + int32_t TestMetricsServiceClient::GetProduct() { return product_; } @@ -99,4 +104,12 @@ return storage_limits_; } +void TestMetricsServiceClient::AllowMetricUploadForUserId(uint64_t user_id) { + allowed_user_ids_.insert(user_id); +} + +void TestMetricsServiceClient::RemoveMetricUploadForUserId(uint64_t user_id) { + allowed_user_ids_.erase(user_id); +} + } // namespace metrics
diff --git a/components/metrics/test/test_metrics_service_client.h b/components/metrics/test/test_metrics_service_client.h index 8baaaca..569fc86 100644 --- a/components/metrics/test/test_metrics_service_client.h +++ b/components/metrics/test/test_metrics_service_client.h
@@ -29,6 +29,7 @@ // MetricsServiceClient: metrics::MetricsService* GetMetricsService() override; void SetMetricsClientId(const std::string& client_id) override; + bool ShouldUploadMetricsForUserId(uint64_t user_id) override; int32_t GetProduct() override; std::string GetApplicationLocale() override; bool GetBrand(std::string* brand_code) override; @@ -49,6 +50,11 @@ bool ShouldResetClientIdsOnClonedInstall() override; MetricsLogStore::StorageLimits GetStorageLimits() const override; + // Adds/removes |user_id| from the set of user ids that have metrics consent + // as true. + void AllowMetricUploadForUserId(uint64_t user_id); + void RemoveMetricUploadForUserId(uint64_t user_id); + const std::string& get_client_id() const { return client_id_; } // Returns a weak ref to the last created uploader. TestMetricsLogUploader* uploader() { return uploader_; } @@ -75,9 +81,10 @@ EnableMetricsDefault enable_default_; bool should_reset_client_ids_on_cloned_install_ = false; MetricsLogStore::StorageLimits storage_limits_; + std::set<uint64_t> allowed_user_ids_; // A weak ref to the last created TestMetricsLogUploader. - TestMetricsLogUploader* uploader_; + TestMetricsLogUploader* uploader_ = nullptr; DISALLOW_COPY_AND_ASSIGN(TestMetricsServiceClient); };
diff --git a/components/metrics/unsent_log_store.cc b/components/metrics/unsent_log_store.cc index e1515c8..92e493e 100644 --- a/components/metrics/unsent_log_store.cc +++ b/components/metrics/unsent_log_store.cc
@@ -32,6 +32,7 @@ const char kLogUnsentCountKey[] = "unsent_samples_count"; const char kLogSentCountKey[] = "sent_samples_count"; const char kLogPersistedSizeInKbKey[] = "unsent_persisted_size_in_kb"; +const char kLogUserIdKey[] = "user_id"; std::string EncodeToBase64(const std::string& to_convert) { DCHECK(to_convert.data()); @@ -53,12 +54,11 @@ default; UnsentLogStore::LogInfo::~LogInfo() = default; -void UnsentLogStore::LogInfo::Init( - UnsentLogStoreMetrics* metrics, - const std::string& log_data, - const std::string& log_timestamp, - const std::string& signing_key, - absl::optional<base::HistogramBase::Count> samples_count) { +void UnsentLogStore::LogInfo::Init(UnsentLogStoreMetrics* metrics, + const std::string& log_data, + const std::string& log_timestamp, + const std::string& signing_key, + const LogMetadata& optional_log_metadata) { DCHECK(!log_data.empty()); if (!compression::GzipCompress(log_data, &compressed_log_data)) { @@ -75,7 +75,7 @@ } timestamp = log_timestamp; - this->samples_count = samples_count; + this->log_metadata = optional_log_metadata; } UnsentLogStore::UnsentLogStore(std::unique_ptr<UnsentLogStoreMetrics> metrics, @@ -135,6 +135,12 @@ return list_[staged_log_index_]->timestamp; } +// Returns the user id of the current staged log. +absl::optional<uint64_t> UnsentLogStore::staged_log_user_id() const { + DCHECK(has_staged_log()); + return list_[staged_log_index_]->log_metadata.user_id; +} + // static bool UnsentLogStore::ComputeHMACForLog(const std::string& log_data, const std::string& signing_key, @@ -166,8 +172,9 @@ void UnsentLogStore::MarkStagedLogAsSent() { DCHECK(has_staged_log()); DCHECK_LT(static_cast<size_t>(staged_log_index_), list_.size()); - if (list_[staged_log_index_]->samples_count.has_value()) - total_samples_sent_ += list_[staged_log_index_]->samples_count.value(); + auto samples_count = list_[staged_log_index_]->log_metadata.samples_count; + if (samples_count.has_value()) + total_samples_sent_ += samples_count.value(); } void UnsentLogStore::TrimAndPersistUnsentLogs() { @@ -178,16 +185,15 @@ void UnsentLogStore::LoadPersistedUnsentLogs() { ReadLogsFromPrefList(*local_state_->GetList(log_data_pref_name_)); - RecordMetaDataMertics(); + RecordMetaDataMetrics(); } -void UnsentLogStore::StoreLog( - const std::string& log_data, - absl::optional<base::HistogramBase::Count> samples_count) { +void UnsentLogStore::StoreLog(const std::string& log_data, + const LogMetadata& log_metadata) { LogInfo info; info.Init(metrics_.get(), log_data, base::NumberToString(base::Time::Now().ToTimeT()), signing_key_, - samples_count); + log_metadata); list_.emplace_back(std::make_unique<LogInfo>(info)); } @@ -197,10 +203,9 @@ return list_[index]->compressed_log_data; } -std::string UnsentLogStore::ReplaceLogAtIndex( - size_t index, - const std::string& new_log_data, - absl::optional<base::HistogramBase::Count> samples_count) { +std::string UnsentLogStore::ReplaceLogAtIndex(size_t index, + const std::string& new_log_data, + const LogMetadata& log_metadata) { DCHECK_GE(index, 0U); DCHECK_LT(index, list_.size()); @@ -214,7 +219,7 @@ // just return a pointer to the logInfo so we could combine the next 3 lines. LogInfo info; info.Init(metrics_.get(), new_log_data, old_timestamp, signing_key_, - samples_count); + log_metadata); list_[index] = std::make_unique<LogInfo>(info); return old_log_data; @@ -263,6 +268,16 @@ info.signature = DecodeFromBase64(info.signature); // timestamp doesn't need to be decoded. + // Extract user id of the log if it exists. + std::string user_id_str; + if (dict->GetString(kLogUserIdKey, &user_id_str)) { + uint64_t user_id; + + // Only initialize the metadata if conversion was successful. + if (base::StringToUint64(DecodeFromBase64(user_id_str), &user_id)) + info.log_metadata.user_id = user_id; + } + list_[i] = std::make_unique<LogInfo>(info); } @@ -332,10 +347,17 @@ dict_value->SetString(kLogDataKey, EncodeToBase64(log->compressed_log_data)); dict_value->SetString(kLogTimestampKey, log->timestamp); + + auto user_id = log->log_metadata.user_id; + if (user_id.has_value()) { + dict_value->SetString( + kLogUserIdKey, EncodeToBase64(base::NumberToString(user_id.value()))); + } list_value->Append(std::move(dict_value)); - if (log->samples_count.has_value()) { - unsent_samples_count += log->samples_count.value(); + auto samples_count = log->log_metadata.samples_count; + if (samples_count.has_value()) { + unsent_samples_count += samples_count.value(); } unsent_persisted_size += log->compressed_log_data.length(); } @@ -360,7 +382,7 @@ base::Value(static_cast<int>(std::ceil(unsent_persisted_size / 1024.0)))); } -void UnsentLogStore::RecordMetaDataMertics() { +void UnsentLogStore::RecordMetaDataMetrics() { if (metadata_pref_name_ == nullptr) return;
diff --git a/components/metrics/unsent_log_store.h b/components/metrics/unsent_log_store.h index af786182..3107650 100644 --- a/components/metrics/unsent_log_store.h +++ b/components/metrics/unsent_log_store.h
@@ -17,6 +17,7 @@ #include "base/metrics/histogram_base.h" #include "base/values.h" #include "components/metrics/log_store.h" +#include "components/metrics/metrics_log.h" #include "third_party/abseil-cpp/absl/types/optional.h" class PrefService; @@ -62,26 +63,25 @@ const std::string& staged_log() const override; const std::string& staged_log_hash() const override; const std::string& staged_log_signature() const override; + absl::optional<uint64_t> staged_log_user_id() const override; void StageNextLog() override; void DiscardStagedLog() override; void MarkStagedLogAsSent() override; void TrimAndPersistUnsentLogs() override; void LoadPersistedUnsentLogs() override; - // Adds a UMA log to the list, |samples_count| is the total number of samples - // in the log (if available). - void StoreLog(const std::string& log_data, - absl::optional<base::HistogramBase::Count> samples_count); + // Adds a UMA log to the list. |log_metadata| refers to metadata associated + // with the log. + void StoreLog(const std::string& log_data, const LogMetadata& log_metadata); // Gets log data at the given index in the list. const std::string& GetLogAtIndex(size_t index); - // Replaces the compressed log at |index| in the store with given log data - // reusing the same timestamp from the original log, and returns old log data. - std::string ReplaceLogAtIndex( - size_t index, - const std::string& new_log_data, - absl::optional<base::HistogramBase::Count> samples_count); + // Replaces the compressed log at |index| in the store with given log data and + // |log_metadata| reusing the same timestamp. + std::string ReplaceLogAtIndex(size_t index, + const std::string& new_log_data, + const LogMetadata& log_metadata); // Deletes all logs, in memory and on disk. void Purge(); @@ -119,7 +119,7 @@ size_t persisted_size) const; // Records the info in |metadata_pref_name_| as UMA metrics. - void RecordMetaDataMertics(); + void RecordMetaDataMetrics(); // An object for recording UMA metrics. std::unique_ptr<UnsentLogStoreMetrics> metrics_; @@ -159,13 +159,14 @@ // serialized log protobuf. A hash and a signature are computed from // |log_data|. The signature is produced using |signing_key|. |log_data| // will be compressed and stored in |compressed_log_data|. |log_timestamp| - // is stored as is. + // is stored as is. |log_metadata| is any optional metadata that will be + // attached to the log. // |metrics| is the parent's metrics_ object, and should not be held. void Init(UnsentLogStoreMetrics* metrics, const std::string& log_data, const std::string& log_timestamp, const std::string& signing_key, - absl::optional<base::HistogramBase::Count> samples_count); + const LogMetadata& log_metadata); // Compressed log data - a serialized protobuf that's been gzipped. std::string compressed_log_data; @@ -182,8 +183,8 @@ // The timestamp of when the log was created as a time_t value. std::string timestamp; - // The total number of samples in this log if applicable. - absl::optional<base::HistogramBase::Count> samples_count; + // Properties of the log. + LogMetadata log_metadata; }; // A list of all of the stored logs, stored with SHA1 hashes to check for // corruption while they are stored in memory.
diff --git a/components/metrics/unsent_log_store_unittest.cc b/components/metrics/unsent_log_store_unittest.cc index c769fc32..30e80ad6 100644 --- a/components/metrics/unsent_log_store_unittest.cc +++ b/components/metrics/unsent_log_store_unittest.cc
@@ -5,6 +5,7 @@ #include "components/metrics/unsent_log_store.h" #include <stddef.h> +#include <limits> #include "base/base64.h" #include "base/hash/sha1.h" @@ -45,8 +46,8 @@ rand_bytes.append(base::RandBytesAsString(min_compressed_size)); std::string base64_data_for_logging; base::Base64Encode(rand_bytes, &base64_data_for_logging); - SCOPED_TRACE(testing::Message() << "Using random data " - << base64_data_for_logging); + SCOPED_TRACE(testing::Message() + << "Using random data " << base64_data_for_logging); return rand_bytes; } @@ -150,7 +151,8 @@ TEST_F(UnsentLogStoreTest, SingleElementLogList) { TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); - unsent_log_store.StoreLog("Hello world!", absl::nullopt); + LogMetadata log_metadata; + unsent_log_store.StoreLog("Hello world!", log_metadata); unsent_log_store.TrimAndPersistUnsentLogs(); TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit); @@ -174,10 +176,11 @@ // bytes. This should leave the logs unchanged. TEST_F(UnsentLogStoreTest, LongButTinyLogList) { TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata; size_t log_count = kLogCountLimit * 5; for (size_t i = 0; i < log_count; ++i) - unsent_log_store.StoreLog("x", absl::nullopt); + unsent_log_store.StoreLog("x", log_metadata); EXPECT_EQ(log_count, unsent_log_store.size()); unsent_log_store.TrimAndPersistUnsentLogs(); @@ -195,6 +198,7 @@ TEST_F(UnsentLogStoreTest, LongButSmallLogList) { size_t log_count = kLogCountLimit * 5; size_t log_size = 50; + LogMetadata log_metadata; std::string first_kept = "First to keep"; first_kept.resize(log_size, ' '); @@ -205,18 +209,18 @@ last_kept.resize(log_size, ' '); // Set the byte limit enough to keep everything but the first two logs. - const size_t min_log_bytes = - Compress(first_kept).length() + Compress(last_kept).length() + - (log_count - 4) * Compress(blank_log).length(); + const size_t min_log_bytes = Compress(first_kept).length() + + Compress(last_kept).length() + + (log_count - 4) * Compress(blank_log).length(); TestUnsentLogStore unsent_log_store(&prefs_, min_log_bytes); - unsent_log_store.StoreLog("one", absl::nullopt); - unsent_log_store.StoreLog("two", absl::nullopt); - unsent_log_store.StoreLog(first_kept, absl::nullopt); + unsent_log_store.StoreLog("one", log_metadata); + unsent_log_store.StoreLog("two", log_metadata); + unsent_log_store.StoreLog(first_kept, log_metadata); for (size_t i = unsent_log_store.size(); i < log_count - 1; ++i) { - unsent_log_store.StoreLog(blank_log, absl::nullopt); + unsent_log_store.StoreLog(blank_log, log_metadata); } - unsent_log_store.StoreLog(last_kept, absl::nullopt); + unsent_log_store.StoreLog(last_kept, log_metadata); size_t original_size = unsent_log_store.size(); unsent_log_store.TrimAndPersistUnsentLogs(); @@ -244,8 +248,9 @@ std::string log_data = GenerateLogWithMinCompressedSize(log_size); TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata; for (size_t i = 0; i < log_count; ++i) { - unsent_log_store.StoreLog(log_data, absl::nullopt); + unsent_log_store.StoreLog(log_data, log_metadata); } unsent_log_store.TrimAndPersistUnsentLogs(); @@ -270,11 +275,12 @@ target_log += GenerateLogWithMinCompressedSize(log_size); std::string log_data = GenerateLogWithMinCompressedSize(log_size); + LogMetadata log_metadata; for (size_t i = 0; i < log_count; ++i) { if (i == log_count - kLogCountLimit) - unsent_log_store.StoreLog(target_log, absl::nullopt); + unsent_log_store.StoreLog(target_log, log_metadata); else - unsent_log_store.StoreLog(log_data, absl::nullopt); + unsent_log_store.StoreLog(log_data, log_metadata); } unsent_log_store.TrimAndPersistUnsentLogs(); @@ -294,16 +300,17 @@ // Check that the store/stage/discard functions work as expected. TEST_F(UnsentLogStoreTest, Staging) { TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata; std::string tmp; EXPECT_FALSE(unsent_log_store.has_staged_log()); - unsent_log_store.StoreLog("one", absl::nullopt); + unsent_log_store.StoreLog("one", log_metadata); EXPECT_FALSE(unsent_log_store.has_staged_log()); - unsent_log_store.StoreLog("two", absl::nullopt); + unsent_log_store.StoreLog("two", log_metadata); unsent_log_store.StageNextLog(); EXPECT_TRUE(unsent_log_store.has_staged_log()); EXPECT_EQ(unsent_log_store.staged_log(), Compress("two")); - unsent_log_store.StoreLog("three", absl::nullopt); + unsent_log_store.StoreLog("three", log_metadata); EXPECT_EQ(unsent_log_store.staged_log(), Compress("two")); EXPECT_EQ(unsent_log_store.size(), 3U); unsent_log_store.DiscardStagedLog(); @@ -323,10 +330,11 @@ // Ensure that the correct log is discarded if new logs are pushed while // a log is staged. TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata; - unsent_log_store.StoreLog("one", absl::nullopt); + unsent_log_store.StoreLog("one", log_metadata); unsent_log_store.StageNextLog(); - unsent_log_store.StoreLog("two", absl::nullopt); + unsent_log_store.StoreLog("two", log_metadata); unsent_log_store.DiscardStagedLog(); unsent_log_store.TrimAndPersistUnsentLogs(); @@ -336,13 +344,13 @@ result_unsent_log_store.ExpectNextLog("two"); } - TEST_F(UnsentLogStoreTest, Hashes) { const char kFooText[] = "foo"; const std::string foo_hash = base::SHA1HashString(kFooText); + LogMetadata log_metadata; TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); - unsent_log_store.StoreLog(kFooText, absl::nullopt); + unsent_log_store.StoreLog(kFooText, log_metadata); unsent_log_store.StageNextLog(); EXPECT_EQ(Compress(kFooText), unsent_log_store.staged_log()); @@ -351,9 +359,10 @@ TEST_F(UnsentLogStoreTest, Signatures) { const char kFooText[] = "foo"; + LogMetadata log_metadata; TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); - unsent_log_store.StoreLog(kFooText, absl::nullopt); + unsent_log_store.StoreLog(kFooText, log_metadata); unsent_log_store.StageNextLog(); EXPECT_EQ(Compress(kFooText), unsent_log_store.staged_log()); @@ -377,9 +386,9 @@ // Test a different key results in a different signature. std::string key = "secret key, don't tell anyone"; TestUnsentLogStore unsent_log_store_different_key(&prefs_, kLogByteLimit, - key); + key); - unsent_log_store_different_key.StoreLog(kFooText, absl::nullopt); + unsent_log_store_different_key.StoreLog(kFooText, log_metadata); unsent_log_store_different_key.StageNextLog(); EXPECT_EQ(Compress(kFooText), unsent_log_store_different_key.staged_log()); @@ -394,6 +403,54 @@ EXPECT_EQ(expected_signature_base64, actual_signature_base64); } +TEST_F(UnsentLogStoreTest, StoreLogWithUserId) { + const char foo_text[] = "foo"; + const uint64_t user_id = 12345L; + + TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata(absl::nullopt, user_id); + unsent_log_store.StoreLog(foo_text, log_metadata); + unsent_log_store.StageNextLog(); + + EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log()); + EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), user_id); + + unsent_log_store.TrimAndPersistUnsentLogs(); + + // Reads persisted logs from new log store. + TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit); + read_unsent_log_store.LoadPersistedUnsentLogs(); + EXPECT_EQ(1U, read_unsent_log_store.size()); + + // Ensure that the user_id was parsed correctly. + read_unsent_log_store.StageNextLog(); + EXPECT_EQ(user_id, read_unsent_log_store.staged_log_user_id().value()); +} + +TEST_F(UnsentLogStoreTest, StoreLogWithLargeUserId) { + const char foo_text[] = "foo"; + const uint64_t large_user_id = std::numeric_limits<uint64_t>::max(); + + TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit); + LogMetadata log_metadata(absl::nullopt, large_user_id); + unsent_log_store.StoreLog(foo_text, log_metadata); + unsent_log_store.StageNextLog(); + + EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log()); + EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), large_user_id); + + unsent_log_store.TrimAndPersistUnsentLogs(); + + // Reads persisted logs from new log store. + TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit); + read_unsent_log_store.LoadPersistedUnsentLogs(); + EXPECT_EQ(1U, read_unsent_log_store.size()); + + // Ensure that the user_id was parsed correctly. + read_unsent_log_store.StageNextLog(); + EXPECT_EQ(large_user_id, read_unsent_log_store.staged_log_user_id().value()); +} + TEST_F(UnsentLogStoreTest, UnsentLogMetadataMetrics) { std::unique_ptr<TestUnsentLogStoreMetrics> metrics = std::make_unique<TestUnsentLogStoreMetrics>(); @@ -418,20 +475,23 @@ // The log without the SampleCount will not be counted to metrics. const char kNoSampleLog[] = "no sample log"; - unsent_log_store.StoreLog( - oversize_log, - absl::make_optional<base::HistogramBase::Count>(kOversizeLogSampleCount)); - unsent_log_store.StoreLog(kNoSampleLog, absl::nullopt); - unsent_log_store.StoreLog( - kFooText, absl::optional<base::HistogramBase::Count>(kFooSampleCount)); + LogMetadata log_metadata_with_oversize_sample(kOversizeLogSampleCount, + absl::nullopt); + unsent_log_store.StoreLog(oversize_log, log_metadata_with_oversize_sample); + + LogMetadata log_metadata_with_no_sample; + unsent_log_store.StoreLog(kNoSampleLog, log_metadata_with_no_sample); + + LogMetadata log_metadata_foo_sample(kFooSampleCount, absl::nullopt); + unsent_log_store.StoreLog(kFooText, log_metadata_foo_sample); + // The foobar_log will be staged first. - unsent_log_store.StoreLog( - foobar_log, - absl::optional<base::HistogramBase::Count>(kFooBarSampleCount)); + LogMetadata log_metadata_foo_bar_sample(kFooBarSampleCount, absl::nullopt); + unsent_log_store.StoreLog(foobar_log, log_metadata_foo_bar_sample); unsent_log_store.TrimAndPersistUnsentLogs(); - unsent_log_store.RecordMetaDataMertics(); + unsent_log_store.RecordMetaDataMetrics(); // The |oversize_log| was ignored, the kNoSampleLog won't be counted to // metrics, EXPECT_EQ(kFooSampleCount + kFooBarSampleCount, m->unsent_samples_count()); @@ -443,7 +503,7 @@ unsent_log_store.MarkStagedLogAsSent(); unsent_log_store.DiscardStagedLog(); unsent_log_store.TrimAndPersistUnsentLogs(); - unsent_log_store.RecordMetaDataMertics(); + unsent_log_store.RecordMetaDataMetrics(); // The |foobar_log| shall be sent. EXPECT_EQ(kFooSampleCount, m->unsent_samples_count()); @@ -454,7 +514,7 @@ unsent_log_store.StageNextLog(); unsent_log_store.DiscardStagedLog(); unsent_log_store.TrimAndPersistUnsentLogs(); - unsent_log_store.RecordMetaDataMertics(); + unsent_log_store.RecordMetaDataMetrics(); // Verify the failed upload wasn't added to the sent samples count. EXPECT_EQ(0, m->unsent_samples_count());
diff --git a/components/nacl/loader/BUILD.gn b/components/nacl/loader/BUILD.gn index 34b43f9..77559ac 100644 --- a/components/nacl/loader/BUILD.gn +++ b/components/nacl/loader/BUILD.gn
@@ -140,7 +140,7 @@ "//url/ipc:url_ipc", ] - if (is_chromeos_ash) { + if (is_chromeos) { # NaCl is not working with compiler-rt in ChromeOS. # Force libgcc as a workaround. See https://crbug.com/761103 ldflags = [
diff --git a/components/services/storage/public/cpp/BUILD.gn b/components/services/storage/public/cpp/BUILD.gn index e735ecb..fca4518 100644 --- a/components/services/storage/public/cpp/BUILD.gn +++ b/components/services/storage/public/cpp/BUILD.gn
@@ -7,6 +7,7 @@ public = [ "constants.h", + "origin_quota_client.h", "quota_client_callback_wrapper.h", "quota_error_or.h", ]
diff --git a/components/services/storage/public/cpp/origin_quota_client.h b/components/services/storage/public/cpp/origin_quota_client.h new file mode 100644 index 0000000..4d59a73 --- /dev/null +++ b/components/services/storage/public/cpp/origin_quota_client.h
@@ -0,0 +1,29 @@ +// 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_SERVICES_STORAGE_PUBLIC_CPP_ORIGIN_QUOTA_CLIENT_H_ +#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_ORIGIN_QUOTA_CLIENT_H_ + +#include "components/services/storage/public/mojom/quota_client.mojom.h" + +namespace storage { + +// Interface for origin based QuotaClient to be inherited by quota managed +// storage APIs that have not implemented Storage Buckets support yet. As +// Storage APIs migrate their implementation to support Storage Buckets, they +// should use the bucket base QuotaClient to be added as part of +// crbug.com/1199417. +// +// TODO(crbug.com/1214066): Once all storage API's have migrated off origin +// based QuotaClient. This class should be removed and all API's should inherit +// from bucket based QuotaClient. +class COMPONENT_EXPORT(STORAGE_SERVICE_PUBLIC) OriginQuotaClient + : public mojom::QuotaClient { + protected: + ~OriginQuotaClient() override = default; +}; + +} // namespace storage + +#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_ORIGIN_QUOTA_CLIENT_H_
diff --git a/components/services/storage/public/cpp/quota_error_or.h b/components/services/storage/public/cpp/quota_error_or.h index ceb35f0c..98ec31e 100644 --- a/components/services/storage/public/cpp/quota_error_or.h +++ b/components/services/storage/public/cpp/quota_error_or.h
@@ -13,6 +13,7 @@ kNone = 0, kUnknownError, kDatabaseError, + kDatabaseNotFound, kEntryExistsError, };
diff --git a/components/signin/public/identity_manager/access_token_constants.cc b/components/signin/public/identity_manager/access_token_constants.cc index 381209fc..cfbe377 100644 --- a/components/signin/public/identity_manager/access_token_constants.cc +++ b/components/signin/public/identity_manager/access_token_constants.cc
@@ -59,9 +59,6 @@ // Required by Permission Request Creator. GaiaConstants::kClassifyUrlKidPermissionOAuth2Scope, - // Required by Enterprise policy extensions. - GaiaConstants::kChromeWebstoreOAuth2Scope, - // Required by ChromeOS only. #if BUILDFLAG(IS_CHROMEOS_ASH) GaiaConstants::kAccountsReauthOAuth2Scope,
diff --git a/components/tab_groups/BUILD.gn b/components/tab_groups/BUILD.gn index 316f14f..a11a4d5 100644 --- a/components/tab_groups/BUILD.gn +++ b/components/tab_groups/BUILD.gn
@@ -17,6 +17,7 @@ deps = [ "//base", "//components/strings", + "//components/tab_groups/public/mojom:mojo_bindings_webui_js", "//skia", "//ui/base", "//ui/gfx",
diff --git a/components/tab_groups/public/mojom/BUILD.gn b/components/tab_groups/public/mojom/BUILD.gn new file mode 100644 index 0000000..bd5a15a --- /dev/null +++ b/components/tab_groups/public/mojom/BUILD.gn
@@ -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. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojo_bindings") { + sources = [ "tab_group_types.mojom" ] + public_deps = [ + "//mojo/public/mojom/base", + "//skia/public/mojom", + ] + + cpp_typemaps = [ + { + types = [ + { + mojom = "tab_groups.mojom.Color" + cpp = "::tab_groups::TabGroupColorId" + }, + ] + traits_headers = [ "tab_groups_mojom_traits.h" ] + }, + ] + + webui_module_path = "" +}
diff --git a/components/tab_groups/public/mojom/OWNERS b/components/tab_groups/public/mojom/OWNERS new file mode 100644 index 0000000..82b3215 --- /dev/null +++ b/components/tab_groups/public/mojom/OWNERS
@@ -0,0 +1,6 @@ +file://chrome/browser/ui/tabs/OWNERS + +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/components/tab_groups/public/mojom/tab_group_types.mojom b/components/tab_groups/public/mojom/tab_group_types.mojom new file mode 100644 index 0000000..56b8922 --- /dev/null +++ b/components/tab_groups/public/mojom/tab_group_types.mojom
@@ -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. + +module tab_groups.mojom; + +// The color Id associated with a given Tab Group. Maps to +// tab_groups::TabGroupColorId in components/tab_groups/tab_group_color.h. +enum Color { + kGrey, + kBlue, + kRed, + kYellow, + kGreen, + kPink, + kPurple, + kCyan, +};
diff --git a/components/tab_groups/public/mojom/tab_groups_mojom_traits.h b/components/tab_groups/public/mojom/tab_groups_mojom_traits.h new file mode 100644 index 0000000..4a6c411 --- /dev/null +++ b/components/tab_groups/public/mojom/tab_groups_mojom_traits.h
@@ -0,0 +1,75 @@ +// 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_TAB_GROUPS_PUBLIC_MOJOM_TAB_GROUPS_MOJOM_TRAITS_H_ +#define COMPONENTS_TAB_GROUPS_PUBLIC_MOJOM_TAB_GROUPS_MOJOM_TRAITS_H_ + +#include "components/tab_groups/public/mojom/tab_group_types.mojom.h" +#include "components/tab_groups/tab_group_color.h" + +namespace mojo { + +template <> +struct EnumTraits<tab_groups::mojom::Color, tab_groups::TabGroupColorId> { + using TabGroupColorId = tab_groups::TabGroupColorId; + using MojoTabGroupColorId = tab_groups::mojom::Color; + + static MojoTabGroupColorId ToMojom(TabGroupColorId input) { + switch (input) { + case TabGroupColorId::kGrey: + return MojoTabGroupColorId::kGrey; + case TabGroupColorId::kBlue: + return MojoTabGroupColorId::kBlue; + case TabGroupColorId::kRed: + return MojoTabGroupColorId::kRed; + case TabGroupColorId::kYellow: + return MojoTabGroupColorId::kYellow; + case TabGroupColorId::kGreen: + return MojoTabGroupColorId::kGreen; + case TabGroupColorId::kPink: + return MojoTabGroupColorId::kPink; + case TabGroupColorId::kPurple: + return MojoTabGroupColorId::kPurple; + case TabGroupColorId::kCyan: + return MojoTabGroupColorId::kCyan; + } + NOTREACHED(); + return MojoTabGroupColorId::kGrey; + } + + static bool FromMojom(MojoTabGroupColorId input, TabGroupColorId* out) { + switch (input) { + case MojoTabGroupColorId::kGrey: + *out = TabGroupColorId::kGrey; + return true; + case MojoTabGroupColorId::kBlue: + *out = TabGroupColorId::kBlue; + return true; + case MojoTabGroupColorId::kRed: + *out = TabGroupColorId::kRed; + return true; + case MojoTabGroupColorId::kYellow: + *out = TabGroupColorId::kYellow; + return true; + case MojoTabGroupColorId::kGreen: + *out = TabGroupColorId::kGreen; + return true; + case MojoTabGroupColorId::kPink: + *out = TabGroupColorId::kPink; + return true; + case MojoTabGroupColorId::kPurple: + *out = TabGroupColorId::kPurple; + return true; + case MojoTabGroupColorId::kCyan: + *out = TabGroupColorId::kCyan; + return true; + } + NOTREACHED(); + return false; + } +}; + +} // namespace mojo + +#endif // COMPONENTS_TAB_GROUPS_PUBLIC_MOJOM_TAB_GROUPS_MOJOM_TRAITS_H_
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm index 2b97c6d3..602574a 100644 --- a/components/translate/ios/browser/ios_translate_driver.mm +++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -87,7 +87,8 @@ translate_manager_->GetLanguageState()->LanguageDetermined( details.adopted_language, true); - if (web_state_) + // Don't offer translation on pages with notranslate meta tag. + if (web_state_ && !details.has_notranslate) translate_manager_->InitiateTranslation(details.adopted_language); for (auto& observer : language_detection_observers())
diff --git a/components/translate/ios/browser/language_detection_controller.h b/components/translate/ios/browser/language_detection_controller.h index bf2eca6..f8633b8 100644 --- a/components/translate/ios/browser/language_detection_controller.h +++ b/components/translate/ios/browser/language_detection_controller.h
@@ -50,7 +50,8 @@ web::WebFrame* sender_frame); // Completion handler used to retrieve the buffered text. - void OnTextRetrieved(const std::string& http_content_language, + void OnTextRetrieved(const bool has_notranslate, + const std::string& http_content_language, const std::string& html_lang, const GURL& url, const base::Value* text_content);
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm index e68966c..d69cd76c 100644 --- a/components/translate/ios/browser/language_detection_controller.mm +++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -94,18 +94,14 @@ *text_captured_command != "languageDetection.textCaptured") { return; } - absl::optional<bool> translation_allowed = - command.FindBoolKey("translationAllowed"); - if (!translation_allowed.value_or(false)) { - // Translation not allowed by the page. Done processing. - return; - } + absl::optional<bool> has_notranslate = command.FindBoolKey("hasNoTranslate"); absl::optional<double> capture_text_time = command.FindDoubleKey("captureTextTime"); const std::string* html_lang = command.FindStringKey("htmlLang"); const std::string* http_content_language = command.FindStringKey("httpContentLanguage"); - if (!capture_text_time.has_value() || !html_lang || !http_content_language) { + if (!has_notranslate.has_value() || !capture_text_time.has_value() || + !html_lang || !http_content_language) { return; } @@ -119,13 +115,14 @@ sender_frame->CallJavaScriptFunction( "languageDetection.retrieveBufferedTextContent", {}, base::BindRepeating(&LanguageDetectionController::OnTextRetrieved, - weak_method_factory_.GetWeakPtr(), + weak_method_factory_.GetWeakPtr(), *has_notranslate, *http_content_language, *html_lang, url), base::TimeDelta::FromMilliseconds( web::kJavaScriptFunctionCallDefaultTimeout)); } void LanguageDetectionController::OnTextRetrieved( + const bool has_notranslate, const std::string& http_content_language, const std::string& html_lang, const GURL& url, @@ -149,6 +146,7 @@ LanguageDetectionDetails details; details.time = base::Time::Now(); details.url = url; + details.has_notranslate = has_notranslate; details.content_language = http_content_language; details.model_detected_language = model_detected_language; details.is_model_reliable = is_model_reliable;
diff --git a/components/translate/ios/browser/resources/language_detection.js b/components/translate/ios/browser/resources/language_detection.js index fc8ed1d..f5b774d 100644 --- a/components/translate/ios/browser/resources/language_detection.js +++ b/components/translate/ios/browser/resources/language_detection.js
@@ -34,21 +34,20 @@ __gCrWeb.languageDetection.activeRequests = 0; /** - * Returns true if translation of the page is allowed. - * Translation is not allowed when a "notranslate" meta tag is defined. - * @return {boolean} true if translation of the page is allowed. + * Searches page elements for "notranslate" meta tag. + * @return {boolean} true if "notranslate" meta tag is defined. */ -__gCrWeb.languageDetection['translationAllowed'] = function() { +__gCrWeb.languageDetection['hasNoTranslate'] = function() { const metaTags = document.getElementsByTagName('meta'); for (let i = 0; i < metaTags.length; ++i) { if (metaTags[i].name === 'google') { if (metaTags[i].content === 'notranslate' || metaTags[i].getAttribute('value') === 'notranslate') { - return false; + return true; } } } - return true; + return false; }; /** @@ -127,43 +126,40 @@ /** * Detects if a page has content that needs translation and informs the native * side. The text content of a page is cached in - * |__gCrWeb.languageDetection.bufferedTextContent| and retrived at a later time - * retrived at a later time directly from the Obj-C side. This is to avoid - * using |invokeOnHost|. + * |__gCrWeb.languageDetection.bufferedTextContent| and retrieved at a later + * time directly from the Obj-C side. This is to avoid using |invokeOnHost|. */ __gCrWeb.languageDetection['detectLanguage'] = function() { - if (!__gCrWeb.languageDetection.translationAllowed()) { - __gCrWeb.message.invokeOnHost({ - 'command': 'languageDetection.textCaptured', - 'translationAllowed': false}); - } else { - // Constant for the maximum length of the extracted text returned by - // |-detectLanguage| to the native side. - // Matches desktop implementation. - // Note: This should stay in sync with the constant in - // language_detection_controller.mm . - const kMaxIndexChars = 65535; - const captureBeginTime = new Date(); - __gCrWeb.languageDetection.activeRequests += 1; - __gCrWeb.languageDetection.bufferedTextContent = - __gCrWeb.languageDetection.getTextContent(document.body, - kMaxIndexChars); - const captureTextTime = - (new Date()).getMilliseconds() - captureBeginTime.getMilliseconds(); - const httpContentLanguage = - __gCrWeb.languageDetection.getMetaContentByHttpEquiv( - 'content-language'); - __gCrWeb.message.invokeOnHost({ - 'command': 'languageDetection.textCaptured', - 'translationAllowed': true, - 'captureTextTime': captureTextTime, - 'htmlLang': document.documentElement.lang, - 'httpContentLanguage': httpContentLanguage}); + // Constant for the maximum length of the extracted text returned by + // |-detectLanguage| to the native side. + // Matches desktop implementation. + // Note: This should stay in sync with the constant in + // language_detection_controller.mm . + const kMaxIndexChars = 65535; + const captureBeginTime = new Date(); + __gCrWeb.languageDetection.activeRequests += 1; + __gCrWeb.languageDetection.bufferedTextContent = + __gCrWeb.languageDetection.getTextContent(document.body, kMaxIndexChars); + const captureTextTime = + (new Date()).getMilliseconds() - captureBeginTime.getMilliseconds(); + const httpContentLanguage = + __gCrWeb.languageDetection.getMetaContentByHttpEquiv('content-language'); + const textCapturedCommand = { + 'command': 'languageDetection.textCaptured', + 'hasNoTranslate': false, + 'captureTextTime': captureTextTime, + 'htmlLang': document.documentElement.lang, + 'httpContentLanguage': httpContentLanguage + }; + + if (__gCrWeb.languageDetection.hasNoTranslate()) { + textCapturedCommand['hasNoTranslate'] = true; } + __gCrWeb.message.invokeOnHost(textCapturedCommand); }; /** - * Retrives the cached text content of a page. Returns it and then purges the + * Retrieves the cached text content of a page. Returns it and then purges the * cache. */ __gCrWeb.languageDetection['retrieveBufferedTextContent'] = function() {
diff --git a/components/ukm/ukm_service.cc b/components/ukm/ukm_service.cc index 515d0db..53fee732 100644 --- a/components/ukm/ukm_service.cc +++ b/components/ukm/ukm_service.cc
@@ -160,7 +160,7 @@ // Replace the compressed log in the store by its filtered version. const std::string old_compressed_log_data = ukm_log_store->ReplaceLogAtIndex(index, reserialized_log_data, - absl::nullopt); + metrics::LogMetadata()); // Reached here only if extensions were found in the log, so data should now // be different after filtering. @@ -430,7 +430,8 @@ std::string serialized_log = UkmService::SerializeReportProtoToString(&report); - reporting_service_.ukm_log_store()->StoreLog(serialized_log, absl::nullopt); + metrics::LogMetadata log_metadata; + reporting_service_.ukm_log_store()->StoreLog(serialized_log, log_metadata); } bool UkmService::ShouldRestrictToWhitelistedEntries() const {
diff --git a/components/ukm/ukm_service_unittest.cc b/components/ukm/ukm_service_unittest.cc index d60e2bc7..9b26dd6 100644 --- a/components/ukm/ukm_service_unittest.cc +++ b/components/ukm/ukm_service_unittest.cc
@@ -306,7 +306,8 @@ report.SerializeToString(&serialized_log); // Makes sure that the serialized ukm report can be parsed. ASSERT_TRUE(UkmService::LogCanBeParsed(serialized_log)); - unsent_log_store->StoreLog(serialized_log, absl::nullopt); + metrics::LogMetadata log_metadata; + unsent_log_store->StoreLog(serialized_log, log_metadata); // Do extension purging. service.PurgeExtensions(); @@ -464,8 +465,7 @@ ++number_of_invocations; }); - UkmService service(&prefs_, &client_, - std::move(provider)); + UkmService service(&prefs_, &client_, std::move(provider)); TestRecordingHelper recorder(&service); service.Initialize(); @@ -505,8 +505,7 @@ .Times(2) .WillRepeatedly([](Report* report) {}); - UkmService service(&prefs_, &client_, - std::move(provider)); + UkmService service(&prefs_, &client_, std::move(provider)); TestRecordingHelper recorder(&service); service.Initialize(); @@ -538,8 +537,7 @@ ProvideSyncedUserNoisedBirthYearAndGenderToReport(testing::_)) .Times(0); - UkmService service(&prefs_, &client_, - std::move(provider)); + UkmService service(&prefs_, &client_, std::move(provider)); TestRecordingHelper recorder(&service); service.Initialize();
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 725c325..f2395ae 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1051,9 +1051,6 @@ case ax::mojom::Role::kAlert: message_id = IDS_AX_ROLE_ALERT; break; - case ax::mojom::Role::kAnchor: - // No role description. - break; case ax::mojom::Role::kApplication: message_id = IDS_AX_ROLE_APPLICATION; break;
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 53477cb0..7029f05 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -623,6 +623,11 @@ RunHtmlTest(FILE_PATH_LITERAL("continuations.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + AccessibilityContinuationsParserSplitsMarkup) { + RunHtmlTest(FILE_PATH_LITERAL("continuations-parser-splits-markup.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityAriaControls) { RunAriaTest(FILE_PATH_LITERAL("aria-controls.html")); }
diff --git a/content/browser/appcache/appcache_quota_client.h b/content/browser/appcache/appcache_quota_client.h index 899a26b..7ec673a 100644 --- a/content/browser/appcache/appcache_quota_client.h +++ b/content/browser/appcache/appcache_quota_client.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" +#include "components/services/storage/public/cpp/origin_quota_client.h" #include "content/browser/appcache/appcache_storage.h" #include "content/common/content_export.h" #include "net/base/completion_repeating_callback.h" @@ -27,12 +27,12 @@ class AppCacheServiceImpl; class AppCacheStorageImpl; -// A QuotaClient implementation to integrate the appcache service -// with the quota management system. The QuotaClient interface is +// An OriginQuotaClient implementation to integrate the appcache service +// with the quota management system. The OriginQuotaClient interface is // used on the IO thread by the quota manager. This class deletes // itself when both the quota manager and the appcache service have // been destroyed. -class AppCacheQuotaClient : public storage::mojom::QuotaClient { +class AppCacheQuotaClient : public storage::OriginQuotaClient { public: using RequestQueue = base::circular_deque<base::OnceClosure>; @@ -41,7 +41,7 @@ ~AppCacheQuotaClient() override; - // mojom::QuotaClient method overrides + // storage::OriginQuotaClient method overrides. void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, GetOriginUsageCallback callback) override;
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc index 668c0c6..0636f49 100644 --- a/content/browser/background_sync/background_sync_manager.cc +++ b/content/browser/background_sync/background_sync_manager.cc
@@ -1362,7 +1362,7 @@ if (devtools_context_->IsRecording( DevToolsBackgroundService::kBackgroundSync)) { devtools_context_->LogBackgroundServiceEventOnCoreThread( - active_version->registration_id(), active_version->origin(), + active_version->registration_id(), active_version->key().origin(), DevToolsBackgroundService::kBackgroundSync, /* event_name= */ "Dispatched sync event", /* instance_id= */ tag, @@ -1404,7 +1404,7 @@ if (devtools_context_->IsRecording( DevToolsBackgroundService::kPeriodicBackgroundSync)) { devtools_context_->LogBackgroundServiceEventOnCoreThread( - active_version->registration_id(), active_version->origin(), + active_version->registration_id(), active_version->key().origin(), DevToolsBackgroundService::kPeriodicBackgroundSync, /* event_name= */ "Dispatched periodicsync event", /* instance_id= */ tag,
diff --git a/content/browser/cache_storage/cache_storage_quota_client.h b/content/browser/cache_storage/cache_storage_quota_client.h index 223f1c7..9d71c65 100644 --- a/content/browser/cache_storage/cache_storage_quota_client.h +++ b/content/browser/cache_storage/cache_storage_quota_client.h
@@ -8,8 +8,8 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" +#include "components/services/storage/public/cpp/origin_quota_client.h" #include "components/services/storage/public/mojom/cache_storage_control.mojom.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" #include "content/common/content_export.h" #include "storage/browser/quota/quota_client_type.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" @@ -25,13 +25,13 @@ // CacheStorageOwner tuple. Created and accessed on the cache storage task // runner. class CONTENT_EXPORT CacheStorageQuotaClient - : public storage::mojom::QuotaClient { + : public storage::OriginQuotaClient { public: CacheStorageQuotaClient(scoped_refptr<CacheStorageManager> cache_manager, storage::mojom::CacheStorageOwner owner); ~CacheStorageQuotaClient() override; - // QuotaClient. + // storage::OriginQuotaClient method overrides. void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, GetOriginUsageCallback callback) override;
diff --git a/content/browser/content_index/content_index_database.cc b/content/browser/content_index/content_index_database.cc index 30427583..32bcdbc 100644 --- a/content/browser/content_index/content_index_database.cc +++ b/content/browser/content_index/content_index_database.cc
@@ -698,13 +698,13 @@ // Don't allow DB operations while the `contentdelete` event is firing. // This is to prevent re-registering the deleted content within the event. - BlockOrigin(service_worker->origin()); + BlockOrigin(service_worker->key().origin()); int request_id = service_worker->StartRequest( ServiceWorkerMetrics::EventType::CONTENT_DELETE, base::BindOnce(&ContentIndexDatabase::DidDispatchEvent, weak_ptr_factory_core_.GetWeakPtr(), - service_worker->origin())); + service_worker->key().origin())); service_worker->endpoint()->DispatchContentDeleteEvent( description_id, service_worker->CreateSimpleEventCallback(request_id));
diff --git a/content/browser/conversions/conversion_storage_sql.cc b/content/browser/conversions/conversion_storage_sql.cc index 8f0d24a..e7efc7f 100644 --- a/content/browser/conversions/conversion_storage_sql.cc +++ b/content/browser/conversions/conversion_storage_sql.cc
@@ -61,12 +61,16 @@ // // Version 6 - 2021/05/06 - https://crrev.com/c/2878235 // -// Version 6 adds the impression.priority column. -const int kCurrentVersionNumber = 6; +// Version 6 adds the impressions.priority column. +// +// Version 7 - 2021/06/03 - https://crrev.com/c/2904386 +// +// Version 7 adds the impressions.impression_site column. +const int kCurrentVersionNumber = 7; // Earliest version which can use a |kCurrentVersionNumber| database // without failing. -const int kCompatibleVersionNumber = 6; +const int kCompatibleVersionNumber = 7; // Latest version of the database that cannot be upgraded to // |kCurrentVersionNumber| without razing the database. No versions are @@ -168,8 +172,8 @@ "(impression_data, impression_origin, conversion_origin, " "conversion_destination, " "reporting_origin, impression_time, expiry_time, source_type, " - "attributed_truthfully, priority) " - "VALUES (?,?,?,?,?,?,?,?,?,?)"; + "attributed_truthfully, priority, impression_site) " + "VALUES (?,?,?,?,?,?,?,?,?,?,?)"; sql::Statement statement( db_->GetCachedStatement(SQL_FROM_HERE, kInsertImpressionSql)); statement.BindString( @@ -184,6 +188,7 @@ statement.BindInt( 8, static_cast<int>(delegate_->SelectAttributionLogic(impression))); statement.BindInt64(9, impression.priority()); + statement.BindString(10, impression.ImpressionSite().Serialize()); statement.Run(); transaction.Commit(); @@ -961,6 +966,8 @@ // |kNavigation|. // |attributed_truthfully| corresponds to the // |StorableImpression::AttributionLogic| enum. + // |impression_site| is used to optimize the lookup of impressions; + // |StorableImpression::ImpressionSite| is always derived from the origin. const char kImpressionTableSql[] = "CREATE TABLE IF NOT EXISTS impressions" "(impression_id INTEGER PRIMARY KEY," @@ -975,7 +982,8 @@ "conversion_destination TEXT NOT NULL," "source_type INTEGER NOT NULL," "attributed_truthfully INTEGER NOT NULL," - "priority INTEGER NOT NULL)"; + "priority INTEGER NOT NULL," + "impression_site TEXT NOT NULL)"; if (!db_->Execute(kImpressionTableSql)) return false; @@ -1007,6 +1015,13 @@ if (!db_->Execute(kImpressionOriginIndexSql)) return false; + // Optimizes `EnsureCapacityForPendingDestinationLimit()`. + const char kImpressionSiteIndexSql[] = + "CREATE INDEX IF NOT EXISTS impression_site_idx " + "ON impressions(active, impression_site, source_type)"; + if (!db_->Execute(kImpressionSiteIndexSql)) + return false; + // All columns in this table are const. |impression_id| is the primary key of // a row in the [impressions] table, [impressions.impression_id]. // |conversion_time| is the time at which the conversion was registered, and
diff --git a/content/browser/conversions/conversion_storage_sql_migrations.cc b/content/browser/conversions/conversion_storage_sql_migrations.cc index dd6043e..2c35e373 100644 --- a/content/browser/conversions/conversion_storage_sql_migrations.cc +++ b/content/browser/conversions/conversion_storage_sql_migrations.cc
@@ -57,6 +57,41 @@ return impressions; } +struct ImpressionIdAndImpressionOrigin { + int64_t impression_id; + url::Origin impression_origin; +}; + +std::vector<ImpressionIdAndImpressionOrigin> +GetImpressionIdAndImpressionOrigins(sql::Database* db, + int64_t start_impression_id, + int num_impressions) { + DCHECK_GE(num_impressions, 0); + const char kGetImpressionsSql[] = + "SELECT impression_id, impression_origin " + "FROM impressions " + "WHERE impression_id >= ? " + "ORDER BY impression_id " + "LIMIT ?"; + + sql::Statement statement( + db->GetCachedStatement(SQL_FROM_HERE, kGetImpressionsSql)); + statement.BindInt64(0, start_impression_id); + statement.BindInt(1, num_impressions); + + std::vector<ImpressionIdAndImpressionOrigin> impressions; + while (statement.Step()) { + int64_t impression_id = statement.ColumnInt64(0); + url::Origin impression_origin = + DeserializeOrigin(statement.ColumnString(1)); + + impressions.push_back({impression_id, std::move(impression_origin)}); + } + if (!statement.Succeeded()) + return {}; + return impressions; +} + } // namespace bool ConversionStorageSqlMigrations::UpgradeSchema( @@ -85,6 +120,10 @@ if (!MigrateToVersion6(conversion_storage, db, meta_table)) return false; } + if (meta_table->GetVersionNumber() == 6) { + if (!MigrateToVersion7(conversion_storage, db, meta_table)) + return false; + } // Add similar if () blocks for new versions here. base::UmaHistogramMediumTimes("Conversions.Storage.MigrationTime", @@ -417,4 +456,130 @@ return transaction.Commit(); } +bool ConversionStorageSqlMigrations::MigrateToVersion7( + ConversionStorageSql* conversion_storage, + sql::Database* db, + sql::MetaTable* meta_table) { + // Wrap each migration in its own transaction. See comment in + // |MigrateToVersion2|. + sql::Transaction transaction(db); + if (!transaction.Begin()) + return false; + + // Add new impression_site column to the impressions table. This follows the + // steps documented at https://sqlite.org/lang_altertable.html#otheralter. + // Other approaches, like using "ALTER ... ADD COLUMN" require setting a + // DEFAULT value for the column which is undesirable. + const char kNewImpressionTableSql[] = + "CREATE TABLE IF NOT EXISTS new_impressions" + "(impression_id INTEGER PRIMARY KEY," + "impression_data TEXT NOT NULL," + "impression_origin TEXT NOT NULL," + "conversion_origin TEXT NOT NULL," + "reporting_origin TEXT NOT NULL," + "impression_time INTEGER NOT NULL," + "expiry_time INTEGER NOT NULL," + "num_conversions INTEGER DEFAULT 0," + "active INTEGER DEFAULT 1," + "conversion_destination TEXT NOT NULL," + "source_type INTEGER NOT NULL," + "attributed_truthfully INTEGER NOT NULL," + "priority INTEGER NOT NULL," + "impression_site TEXT NOT NULL)"; + if (!db->Execute(kNewImpressionTableSql)) + return false; + + // Transfer the existing rows to the new table, inserting placeholder values + // for the impression_site column. + const char kPopulateNewImpressionTableSql[] = + "INSERT INTO new_impressions SELECT " + "impression_id,impression_data,impression_origin," + "conversion_origin,reporting_origin,impression_time," + "expiry_time,num_conversions,active,conversion_destination,source_type," + "attributed_truthfully,priority,'' " + "FROM impressions"; + sql::Statement populate_statement( + db->GetCachedStatement(SQL_FROM_HERE, kPopulateNewImpressionTableSql)); + if (!populate_statement.Run()) + return false; + + const char kDropOldImpressionTableSql[] = "DROP TABLE impressions"; + if (!db->Execute(kDropOldImpressionTableSql)) + return false; + + const char kRenameImpressionTableSql[] = + "ALTER TABLE new_impressions RENAME TO impressions"; + if (!db->Execute(kRenameImpressionTableSql)) + return false; + + // Update each of the impression rows to have the correct associated + // impression_site. + // + // We update `kNumImpressionsPerUpdate` rows at a time, to avoid pulling the + // entire impressions table into memory. + int64_t start_impression_id = 0; + const size_t kNumImpressionsPerUpdate = 100u; + std::vector<ImpressionIdAndImpressionOrigin> impressions = + GetImpressionIdAndImpressionOrigins(db, start_impression_id, + kNumImpressionsPerUpdate); + + const char kUpdateImpressionSiteSql[] = + "UPDATE impressions SET impression_site = ? WHERE impression_id = ?"; + sql::Statement update_impression_site_statement( + db->GetCachedStatement(SQL_FROM_HERE, kUpdateImpressionSiteSql)); + + while (!impressions.empty()) { + // Perform the column updates for each row we pulled into memory. + for (const auto& impression : impressions) { + update_impression_site_statement.Reset(/*clear_bound_vars=*/true); + + // The impression site is derived from the impression origin dynamically. + update_impression_site_statement.BindString( + 0, net::SchemefulSite(impression.impression_origin).Serialize()); + update_impression_site_statement.BindInt64(1, impression.impression_id); + if (!update_impression_site_statement.Run()) + return false; + + // Track the largest row id. This is more efficient than sorting all the + // rows. + if (impression.impression_id > start_impression_id) + start_impression_id = impression.impression_id; + } + + // Fetch the next batch of rows from the database. + start_impression_id += 1; + impressions = GetImpressionIdAndImpressionOrigins(db, start_impression_id, + kNumImpressionsPerUpdate); + } + + // Create the pre-existing impression table indices on the new table. + const char kImpressionExpiryIndexSql[] = + "CREATE INDEX IF NOT EXISTS impression_expiry_idx " + "ON impressions(expiry_time)"; + if (!db->Execute(kImpressionExpiryIndexSql)) + return false; + + const char kImpressionOriginIndexSql[] = + "CREATE INDEX IF NOT EXISTS impression_origin_idx " + "ON impressions(impression_origin)"; + if (!db->Execute(kImpressionOriginIndexSql)) + return false; + + const char kConversionDestinationIndexSql[] = + "CREATE INDEX IF NOT EXISTS conversion_destination_idx " + "ON impressions(active, conversion_destination, reporting_origin)"; + if (!db->Execute(kConversionDestinationIndexSql)) + return false; + + // Create the new impression table index. + const char kImpressionSiteIndexSql[] = + "CREATE INDEX IF NOT EXISTS impression_site_idx " + "ON impressions(active, impression_site, source_type)"; + if (!db->Execute(kImpressionSiteIndexSql)) + return false; + + meta_table->SetVersionNumber(7); + return transaction.Commit(); +} + } // namespace content
diff --git a/content/browser/conversions/conversion_storage_sql_migrations.h b/content/browser/conversions/conversion_storage_sql_migrations.h index 6492786..6dc8429 100644 --- a/content/browser/conversions/conversion_storage_sql_migrations.h +++ b/content/browser/conversions/conversion_storage_sql_migrations.h
@@ -70,6 +70,9 @@ static bool MigrateToVersion6(ConversionStorageSql* conversion_storage, sql::Database* db, sql::MetaTable* meta_table); + static bool MigrateToVersion7(ConversionStorageSql* conversion_storage, + sql::Database* db, + sql::MetaTable* meta_table); }; } // namespace content
diff --git a/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc b/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc index a7f2fa8..40f7d62e 100644 --- a/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc +++ b/content/browser/conversions/conversion_storage_sql_migrations_unittest.cc
@@ -29,7 +29,7 @@ return output; } -const int kCurrentVersionNumber = 6; +const int kCurrentVersionNumber = 7; } // namespace @@ -57,7 +57,7 @@ std::string GetCurrentSchema() { base::FilePath current_version_path = temp_directory_.GetPath().Append( FILE_PATH_LITERAL("TestCurrentVersion.db")); - LoadDatabase(FILE_PATH_LITERAL("version_6.sql"), current_version_path); + LoadDatabase(FILE_PATH_LITERAL("version_7.sql"), current_version_path); sql::Database db; EXPECT_TRUE(db.Open(current_version_path)); return db.GetSchema(); @@ -402,4 +402,55 @@ histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); } +TEST_F(ConversionStorageSqlMigrationsTest, MigrateVersion6ToCurrent) { + base::HistogramTester histograms; + LoadDatabase(FILE_PATH_LITERAL("version_6.sql"), DbPath()); + + // Verify pre-conditions. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + ASSERT_FALSE(db.DoesColumnExist("impressions", "impression_site")); + } + + MigrateDatabase(); + + // Verify schema is current. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + // Check version. + EXPECT_EQ(kCurrentVersionNumber, VersionFromDatabase(&db)); + + // Compare without quotes as sometimes migrations cause table names to be + // string literals. + EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + + // Check that the relevant schema changes are made. + EXPECT_TRUE(db.DoesColumnExist("impressions", "impression_site")); + + // Verify that data is preserved across the migration. + size_t rows = 0; + sql::test::CountTableRows(&db, "impressions", &rows); + EXPECT_EQ(2u, rows); + + sql::Statement s(db.GetUniqueStatement( + "SELECT impression_origin, impression_site FROM impressions")); + + ASSERT_TRUE(s.Step()); + ASSERT_EQ("https://a.impression.test", s.ColumnString(0)); + ASSERT_EQ("https://impression.test", s.ColumnString(1)); + ASSERT_TRUE(s.Step()); + ASSERT_EQ("https://b.impression.test", s.ColumnString(0)); + ASSERT_EQ("https://impression.test", s.ColumnString(1)); + ASSERT_FALSE(s.Step()); + } + + // DB migration histograms should be recorded. + histograms.ExpectTotalCount("Conversions.Storage.CreationTime", 0); + histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); +} + } // namespace content
diff --git a/content/browser/conversions/conversion_storage_sql_unittest.cc b/content/browser/conversions/conversion_storage_sql_unittest.cc index b2d0dea..12435d4 100644 --- a/content/browser/conversions/conversion_storage_sql_unittest.cc +++ b/content/browser/conversions/conversion_storage_sql_unittest.cc
@@ -104,11 +104,11 @@ EXPECT_EQ(4u, sql::test::CountSQLTables(&raw_db)); // [conversion_domain_idx], [impression_expiry_idx], - // [impression_origin_idx], [conversion_report_time_idx], - // [conversion_impression_id_idx], [rate_limit_origin_type_idx], - // [rate_limit_conversion_time_idx], [rate_limit_impression_id_idx] and the - // meta table index. - EXPECT_EQ(9u, sql::test::CountSQLIndices(&raw_db)); + // [impression_origin_idx], [impression_site_idx], + // [conversion_report_time_idx], [conversion_impression_id_idx], + // [rate_limit_origin_type_idx], [rate_limit_conversion_time_idx], + // [rate_limit_impression_id_idx] and the meta table index. + EXPECT_EQ(10u, sql::test::CountSQLIndices(&raw_db)); } }
diff --git a/content/browser/conversions/conversion_storage_unittest.cc b/content/browser/conversions/conversion_storage_unittest.cc index 0655f3a..40ac328 100644 --- a/content/browser/conversions/conversion_storage_unittest.cc +++ b/content/browser/conversions/conversion_storage_unittest.cc
@@ -775,6 +775,44 @@ EXPECT_TRUE(ReportsEqual({expected_report, expected_report}, actual_reports)); } +TEST_F(ConversionStorageTest, + MaxAttributionReportsBetweenSites_RespectsSourceType) { + delegate()->set_rate_limits({ + .time_window = base::TimeDelta::Max(), + .max_attributions_per_window = 1, + }); + + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()) + .SetSourceType(StorableImpression::SourceType::kNavigation) + .Build()); + EXPECT_TRUE( + storage()->MaybeCreateAndStoreConversionReport(DefaultConversion())); + + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()) + .SetSourceType(StorableImpression::SourceType::kEvent) + .Build()); + // This would fail if the source types had a combined limit or the incorrect + // source type were stored. + EXPECT_TRUE( + storage()->MaybeCreateAndStoreConversionReport(DefaultConversion())); + + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()) + .SetSourceType(StorableImpression::SourceType::kEvent) + .Build()); + EXPECT_FALSE( + storage()->MaybeCreateAndStoreConversionReport(DefaultConversion())); + + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()) + .SetSourceType(StorableImpression::SourceType::kNavigation) + .Build()); + EXPECT_FALSE( + storage()->MaybeCreateAndStoreConversionReport(DefaultConversion())); +} + TEST_F(ConversionStorageTest, NeverAttributeImpression_ReportNotStored) { delegate()->set_attribution_logic( StorableImpression::AttributionLogic::kNever);
diff --git a/content/browser/conversions/rate_limit_table.cc b/content/browser/conversions/rate_limit_table.cc index ce96b32..299f0f91 100644 --- a/content/browser/conversions/rate_limit_table.cc +++ b/content/browser/conversions/rate_limit_table.cc
@@ -29,7 +29,8 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // All columns in this table are const. - // |attribution_type| is the type of the report, currently always kNavigation. + // |attribution_type| corresponds to the `StorableImpression::SourceType` + // of the impression. // |impression_id| is the primary key of a row in the |impressions| table, // though the row may not exist. // |impression_site| is the eTLD+1 of the impression. @@ -87,7 +88,7 @@ "VALUES(?,?,?,?,?,?,?)"; sql::Statement statement( db->GetCachedStatement(SQL_FROM_HERE, kStoreRateLimitSql)); - statement.BindInt(0, static_cast<int>(AttributionType::kNavigation)); + statement.BindInt(0, static_cast<int>(report.impression.source_type())); statement.BindInt64(1, *report.impression.impression_id()); statement.BindString( 2, net::SchemefulSite(report.impression.impression_origin()).Serialize()); @@ -116,7 +117,7 @@ "AND conversion_time > ?"; sql::Statement statement( db->GetCachedStatement(SQL_FROM_HERE, kAttributionAllowedSql)); - statement.BindInt(0, static_cast<int>(AttributionType::kNavigation)); + statement.BindInt(0, static_cast<int>(report.impression.source_type())); statement.BindString( 1, net::SchemefulSite(report.impression.impression_origin()).Serialize()); statement.BindString(2,
diff --git a/content/browser/conversions/rate_limit_table.h b/content/browser/conversions/rate_limit_table.h index 1ec8356..6308196d 100644 --- a/content/browser/conversions/rate_limit_table.h +++ b/content/browser/conversions/rate_limit_table.h
@@ -29,11 +29,6 @@ // destroyed on the same sequence. The sequence must outlive |this|. class CONTENT_EXPORT RateLimitTable { public: - enum class AttributionType { - kNavigation = 0, - kMaxValue = kNavigation, - }; - RateLimitTable(const ConversionStorage::Delegate* delegate, const base::Clock* clock); RateLimitTable(const RateLimitTable& other) = delete;
diff --git a/content/browser/conversions/rate_limit_table_unittest.cc b/content/browser/conversions/rate_limit_table_unittest.cc index b5bf9c2..7c6d9d9 100644 --- a/content/browser/conversions/rate_limit_table_unittest.cc +++ b/content/browser/conversions/rate_limit_table_unittest.cc
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "content/browser/conversions/conversion_report.h" #include "content/browser/conversions/conversion_test_utils.h" +#include "content/browser/conversions/storable_impression.h" #include "sql/database.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -30,13 +31,17 @@ table_ = std::make_unique<RateLimitTable>(delegate_.get(), &clock_); } - ConversionReport NewConversionReport(const url::Origin& impression_origin, - const url::Origin& conversion_origin, - int64_t impression_id = 0) { + ConversionReport NewConversionReport( + const url::Origin& impression_origin, + const url::Origin& conversion_origin, + int64_t impression_id = 0, + StorableImpression::SourceType source_type = + StorableImpression::SourceType::kNavigation) { return ConversionReport(ImpressionBuilder(clock()->Now()) .SetImpressionOrigin(impression_origin) .SetConversionOrigin(conversion_origin) .SetImpressionId(impression_id) + .SetSourceType(source_type) .Build(), /*conversion_data=*/0, /*conversion_time=*/clock()->Now(), @@ -148,15 +153,15 @@ const auto report_b_c = NewConversionReport(example_b, example_c); // conversion doesn't match const auto report_a_b = NewConversionReport(example_a, example_b); - // neither impression and conversion match - const auto report_b_d = NewConversionReport(example_a, example_b); + // neither impression nor conversion match + const auto report_b_a = NewConversionReport(example_b, example_a); base::Time now = clock()->Now(); EXPECT_FALSE(table()->IsAttributionAllowed(&db, report_a_c, now)); EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_a_d, now)); EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_c, now)); EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_a_b, now)); - EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_d, now)); + EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_a, now)); // Expire the first row above by advancing to +10d. clock()->Advance(base::TimeDelta::FromDays(4)); @@ -165,11 +170,56 @@ EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_a_d, now)); EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_c, now)); EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_a_b, now)); - EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_d, now)); + EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_b_a, now)); EXPECT_EQ(3u, GetRateLimitRows(&db)); } +TEST_F(RateLimitTableTest, IsAttributionAllowed_SourceTypesIndependent) { + // Tests that limits are calculated independently for each + // `StorableImpression::SourceType`. In the future, we may change this so that + // there is a combined calculation but each source type is weighted + // differently. + + sql::Database db; + EXPECT_TRUE(db.Open(db_path())); + EXPECT_TRUE(table()->CreateTable(&db)); + + delegate()->set_rate_limits({ + .time_window = base::TimeDelta::FromDays(2), + .max_attributions_per_window = 2, + }); + + const url::Origin example_a = url::Origin::Create(GURL("https://a.example/")); + const url::Origin example_c = url::Origin::Create(GURL("https://c.example/")); + + const auto report_navigation = + NewConversionReport(example_a, example_c, /*impression_id=*/0, + StorableImpression::SourceType::kNavigation); + const auto report_event = + NewConversionReport(example_a, example_c, /*impression_id=*/0, + StorableImpression::SourceType::kEvent); + + // Add distinct source types on the same origin to ensure independence. + EXPECT_TRUE(table()->AddRateLimit(&db, report_navigation)); + EXPECT_TRUE(table()->AddRateLimit(&db, report_event)); + EXPECT_EQ(2u, GetRateLimitRows(&db)); + + base::Time now = clock()->Now(); + EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_navigation, now)); + EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_event, now)); + + EXPECT_TRUE(table()->AddRateLimit(&db, report_navigation)); + EXPECT_EQ(3u, GetRateLimitRows(&db)); + EXPECT_FALSE(table()->IsAttributionAllowed(&db, report_navigation, now)); + EXPECT_TRUE(table()->IsAttributionAllowed(&db, report_event, now)); + + EXPECT_TRUE(table()->AddRateLimit(&db, report_event)); + EXPECT_EQ(4u, GetRateLimitRows(&db)); + EXPECT_FALSE(table()->IsAttributionAllowed(&db, report_navigation, now)); + EXPECT_FALSE(table()->IsAttributionAllowed(&db, report_event, now)); +} + TEST_F(RateLimitTableTest, IsAttributionAllowed_ConversionDestinationSubdomains) { sql::Database db;
diff --git a/content/browser/conversions/storable_impression.cc b/content/browser/conversions/storable_impression.cc index bf9fe85..e607bf8 100644 --- a/content/browser/conversions/storable_impression.cc +++ b/content/browser/conversions/storable_impression.cc
@@ -43,4 +43,8 @@ return net::SchemefulSite(conversion_origin_); } +net::SchemefulSite StorableImpression::ImpressionSite() const { + return net::SchemefulSite(impression_origin_); +} + } // namespace content
diff --git a/content/browser/conversions/storable_impression.h b/content/browser/conversions/storable_impression.h index 19a4063..2bdcc03c 100644 --- a/content/browser/conversions/storable_impression.h +++ b/content/browser/conversions/storable_impression.h
@@ -77,9 +77,15 @@ // Returns the schemeful site of |conversion_origin|. // // TODO(johnidel): Consider storing the SchemefulSite as a separate member so - // that we avoid unnecessary copies of |conversion_origin|. + // that we avoid unnecessary copies of |conversion_origin_|. net::SchemefulSite ConversionDestination() const; + // Returns the schemeful site of |impression_origin|. + // + // TODO(johnidel): Consider storing the SchemefulSite as a separate member so + // that we avoid unnecessary copies of |impression_origin_|. + net::SchemefulSite ImpressionSite() const; + private: uint64_t impression_data_; url::Origin impression_origin_;
diff --git a/content/browser/indexed_db/indexed_db_quota_client.h b/content/browser/indexed_db/indexed_db_quota_client.h index a15862e..39c46f0 100644 --- a/content/browser/indexed_db/indexed_db_quota_client.h +++ b/content/browser/indexed_db/indexed_db_quota_client.h
@@ -12,7 +12,7 @@ #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" +#include "components/services/storage/public/cpp/origin_quota_client.h" #include "content/common/content_export.h" #include "storage/browser/quota/quota_client_type.h" #include "storage/browser/quota/quota_task.h" @@ -25,7 +25,7 @@ // Integrates IndexedDB with the quota management system. // // Each instance is owned by an IndexedDBContextImpl. -class IndexedDBQuotaClient : public storage::mojom::QuotaClient { +class IndexedDBQuotaClient : public storage::OriginQuotaClient { public: CONTENT_EXPORT explicit IndexedDBQuotaClient( IndexedDBContextImpl& indexed_db_context); @@ -35,7 +35,7 @@ CONTENT_EXPORT ~IndexedDBQuotaClient() override; - // QuotaClient implementation: + // storage::OriginQuotaClient implementation: void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, GetOriginUsageCallback callback) override;
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc index adc43f6..2254ddef 100644 --- a/content/browser/interest_group/auction_runner.cc +++ b/content/browser/interest_group/auction_runner.cc
@@ -146,7 +146,7 @@ } void AuctionRunner::StartBidding() { - // Auctions are only run when there are bidders participating. As-is, and + // Auctions are only run when there are bidders participating. As-is, an // empty bidder vector here would result in synchronously calling back into // the creator, which isn't allowed. DCHECK(!bid_states_.empty()); @@ -157,6 +157,8 @@ auction_worklet::mojom::BiddingInterestGroup* bidder = bid_state.bidder.get(); + DCHECK_EQ(bid_state.state, BidState::State::kWaitingToLoadWorklet); + // Assemble list of URLs the bidder can request. // TODO(mmenke): This largely duplicates logic in the auction worklet @@ -196,6 +198,8 @@ bid_state.bidder->group->bidding_url.value_or(GURL()), trusted_bidding_signals_full_url); + bid_state.state = BidState::State::kGeneratingBid; + delegate_->GetWorkletService()->LoadBidderWorkletAndGenerateBid( bid_state.bidder_worklet.BindNewPipeAndPassReceiver(), std::move(url_loader_factory), bidder->Clone(), @@ -240,8 +244,7 @@ const std::vector<std::string>& errors) { DCHECK(!state->bid_result); DCHECK_GT(outstanding_bids_, 0); - - --outstanding_bids_; + DCHECK_EQ(state->state, BidState::State::kGeneratingBid); errors_.insert(errors_.end(), errors.begin(), errors.end()); @@ -252,19 +255,25 @@ 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) { + // On failure, close the worklet pipe. state->bidder_worklet.reset(); - } else { - state->bidder_worklet.set_disconnect_handler(base::OnceClosure()); + + state->state = BidState::State::kScoringComplete; + --outstanding_bids_; + MaybeCompleteAuction(); + return; } - state->bid_result = std::move(bid); + // On success, clear the disconnect handler. After generating a bid, a crashed + // bidder only matters if it's the winning bidder that crashed. That's checked + // for at the end of the auction. + state->bidder_worklet.set_disconnect_handler(base::OnceClosure()); - if (ReadyToScore()) - ScoreOne(); + state->bid_result = std::move(bid); + state->state = BidState::State::kWaitingOnSellerWorkletLoad; + if (seller_loaded_) + ScoreBid(state); } void AuctionRunner::OnSellerWorkletLoaded( @@ -274,8 +283,15 @@ if (load_result) { seller_loaded_ = true; - if (ReadyToScore()) - ScoreOne(); + // Start scoring any bids that were waiting on the seller worklet to load. + for (BidState& state : bid_states_) { + // Bids can be complete at this point (if no bid was offered, or on + // error), but they can't be scoring a bid. + DCHECK_NE(state.state, BidState::State::kSellerScoringBid); + + if (state.state == BidState::State::kWaitingOnSellerWorkletLoad) + ScoreBid(&state); + } } else { // Failed to load the seller/auction script --- nothing useful can be // done, so abort, possibly cancelling other fetches, so we don't waste @@ -284,43 +300,42 @@ } } -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) { +void AuctionRunner::ScoreBid(BidState* state) { + DCHECK_EQ(state->state, BidState::State::kWaitingOnSellerWorkletLoad); + state->state = BidState::State::kSellerScoringBid; 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())); + weak_ptr_factory_.GetWeakPtr(), state)); } -void AuctionRunner::OnBidScored(double score, +void AuctionRunner::OnBidScored(BidState* state, + double score, const std::vector<std::string>& errors) { - bid_states_[seller_considering_].seller_score = score; + DCHECK_EQ(state->state, BidState::State::kSellerScoringBid); + state->seller_score = score; + + // Check if this is the top bidder. If not, unload its worklet. + // + // TODO(morlovich): What if there is a tie? + if (score > 0 && (!top_bidder_ || score > top_bidder_->seller_score)) { + // If this bidder out scored a previous winning bidder, unload that bidder's + // worklet. + if (top_bidder_) + top_bidder_->bidder_worklet.reset(); + top_bidder_ = state; + } else { + state->bidder_worklet.reset(); + } + + --outstanding_bids_; + state->state = BidState::State::kScoringComplete; + errors_.insert(errors_.end(), errors.begin(), errors.end()); - ++seller_considering_; - ScoreOne(); + MaybeCompleteAuction(); } std::string AuctionRunner::AdRenderFingerprint(const BidState* state) { @@ -342,49 +357,46 @@ return absl::nullopt; } -void AuctionRunner::CompleteAuction() { - double best_bid_score = 0.0; - BidState* best_bid = nullptr; +void AuctionRunner::MaybeCompleteAuction() { + if (!AllBidsScored()) + return; - // Find the best bid, if any, and record the bid of all bidders that made a - // bid. Record bidders at this point because the auction has successfully - // completed, and need to record bids even in the case the seller rejected all - // bids. + // Record which interest groups bid. // - // TODO(morlovich): What if there is a tie? + // TODO(mmenke): Maybe this should be recorded at bid time, and the interest + // group thrown away if it's not the top bid? for (BidState& bid_state : bid_states_) { if (bid_state.bid_result) { interest_group_manager_->RecordInterestGroupBid( bid_state.bidder->group->owner, bid_state.bidder->group->name); - if (bid_state.seller_score > best_bid_score) { - best_bid_score = bid_state.seller_score; - best_bid = &bid_state; - } } } - if (best_bid) { + if (top_bidder_) { // Will eventually send a report to the seller and clean up `this`. - ReportSellerResult(best_bid); + ReportSellerResult(); } else { FailAuction(); } } -void AuctionRunner::ReportSellerResult(BidState* best_bid) { - DCHECK(best_bid->bid_result); - DCHECK_GT(best_bid->seller_score, 0); +void AuctionRunner::ReportSellerResult() { + DCHECK(top_bidder_); + + DCHECK(top_bidder_->bid_result); + DCHECK_GT(top_bidder_->seller_score, 0); + DCHECK(top_bidder_->bidder_worklet); + 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, + top_bidder_->bidder->group->owner, top_bidder_->bid_result->render_url, + AdRenderFingerprint(top_bidder_), top_bidder_->bid_result->bid, + top_bidder_->seller_score, base::BindOnce(&AuctionRunner::OnReportSellerResultComplete, - weak_ptr_factory_.GetWeakPtr(), best_bid)); + weak_ptr_factory_.GetWeakPtr())); } 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) { @@ -398,13 +410,12 @@ return; } - ReportBidWin(best_bid, signals_for_winner); + ReportBidWin(signals_for_winner); } void AuctionRunner::ReportBidWin( - BidState* best_bid, const absl::optional<std::string>& signals_for_winner) { - CHECK(best_bid->bid_result); + DCHECK(top_bidder_->bid_result); std::string signals_for_winner_arg; if (signals_for_winner) { signals_for_winner_arg = *signals_for_winner; @@ -422,26 +433,25 @@ // 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). - if (!best_bid->bidder_worklet.is_connected()) { + if (!top_bidder_->bidder_worklet.is_connected()) { FailAuctionWithError( - base::StrCat({best_bid->bidder->group->bidding_url->spec(), + base::StrCat({top_bidder_->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, + top_bidder_->bidder_worklet->ReportWin( + signals_for_winner_arg, top_bidder_->bid_result->render_url, + AdRenderFingerprint(top_bidder_), top_bidder_->bid_result->bid, base::BindOnce(&AuctionRunner::OnReportBidWinComplete, - weak_ptr_factory_.GetWeakPtr(), best_bid)); - best_bid->bidder_worklet.set_disconnect_handler(base::BindOnce( + weak_ptr_factory_.GetWeakPtr())); + top_bidder_->bidder_worklet.set_disconnect_handler(base::BindOnce( &AuctionRunner::FailAuctionWithError, weak_ptr_factory_.GetWeakPtr(), - base::StrCat({best_bid->bidder->group->bidding_url->spec(), + base::StrCat({top_bidder_->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)) { @@ -452,7 +462,7 @@ bidder_report_url_ = bidder_report_url; errors_.insert(errors_.end(), errors.begin(), errors.end()); - ReportSuccess(best_bid); + ReportSuccess(); } void AuctionRunner::FailAuction() { @@ -468,27 +478,29 @@ FailAuction(); } -void AuctionRunner::ReportSuccess(const BidState* state) { +void AuctionRunner::ReportSuccess() { DCHECK(callback_); - DCHECK(state->bid_result); + DCHECK(top_bidder_->bid_result); ClosePipes(); std::string ad_metadata; - if (state->bid_ad->metadata) { + if (top_bidder_->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()); + top_bidder_->bid_result->render_url.spec().c_str(), + top_bidder_->bid_ad->metadata.value().c_str()); } else { - ad_metadata = base::StringPrintf( - R"({"render_url":"%s"})", state->bid_result->render_url.spec().c_str()); + ad_metadata = + base::StringPrintf(R"({"render_url":"%s"})", + top_bidder_->bid_result->render_url.spec().c_str()); } interest_group_manager_->RecordInterestGroupWin( - state->bidder->group->owner, state->bidder->group->name, ad_metadata); + top_bidder_->bidder->group->owner, top_bidder_->bidder->group->name, + ad_metadata); - std::move(callback_).Run(this, state->bid_result->render_url, + std::move(callback_).Run(this, top_bidder_->bid_result->render_url, std::move(bidder_report_url_), std::move(seller_report_url_), std::move(errors_)); }
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h index 4a71399..4366ce48 100644 --- a/content/browser/interest_group/auction_runner.h +++ b/content/browser/interest_group/auction_runner.h
@@ -31,19 +31,6 @@ // 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. @@ -121,6 +108,30 @@ private: struct BidState { + enum class State { + // Waiting for all the interest groups to load before starting to load + // worklets. + // + // TODO(mmenke): Consider removing this phase. + kWaitingToLoadWorklet, + + // Loading the bidder worklet script / trusted data and generating the + // bid. + kGeneratingBid, + + // Waiting on the seller worklet to load. + kWaitingOnSellerWorkletLoad, + + // Waiting on the seller worklet to score the bid. + kSellerScoringBid, + + // Seller worklet has completed scoring the bid, or doesn't need to. If + // this is not potentially the winning bidder, the worklet has been + // unloaded. Otherwise, the worklet is still in memory, as it may still be + // necessary to call reporting methods, if this is the winning bidder. + kScoringComplete, + }; + BidState(); BidState(BidState&&); ~BidState(); @@ -131,6 +142,8 @@ BidState(BidState&) = delete; BidState& operator=(BidState&) = delete; + State state = State::kWaitingToLoadWorklet; + auction_worklet::mojom::BiddingInterestGroupPtr bidder; // URLLoaderFactory proxy class configured only to load the URLs the bidder @@ -174,38 +187,35 @@ 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_; } + bool AllBidsScored() const { return outstanding_bids_ == 0; } 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); + // Calls into the seller asynchronously to score the passed in bid. + void ScoreBid(BidState* state); // Callback from ScoreBid(). - void OnBidScored(double score, const std::vector<std::string>& errors); + void OnBidScored(BidState* state, + 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(); + // If there are no `outstanding_bids_`, starts starts completing the auction, + // either invoking `callback_` or calling reporting methods on worklets. + // Consumer must be able to safely delete `this` when the callback is invoked. + void MaybeCompleteAuction(); // 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 ReportSellerResult(); 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, - const absl::optional<std::string>& signals_for_winner); - void OnReportBidWinComplete(const BidState* best_bid, - const absl::optional<GURL>& bidder_report_url, + void ReportBidWin(const absl::optional<std::string>& signals_for_winner); + void OnReportBidWinComplete(const absl::optional<GURL>& bidder_report_url, const std::vector<std::string>& error_msgs); // These complete the auction, invoking `callback_` and preventing any future @@ -214,7 +224,7 @@ void FailAuction(); // Appends `error` to `errors_` before calling FailAuciton(). void FailAuctionWithError(std::string error); - void ReportSuccess(const BidState* state); + void ReportSuccess(); // Closes all open pipes, to avoid receiving any Mojo callbacks after // completion. @@ -234,13 +244,21 @@ 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_; // State of all loaded bidders. + // Number of bids which the seller has not yet scored. These bids may be + // fetching URLs, generating bids, waiting for the seller worklet to load, or + // the seller worklet may be scoring their bids. + int outstanding_bids_; + // State of all loaded interest groups. + std::vector<BidState> bid_states_; // 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(); + // The bidder with the highest scoring bid so far. No other scored bidder + // worklet can win the auction, so the other worklets are all unloaded right + // after scoring. + BidState* top_bidder_ = nullptr; + // URLLoaderFactory proxy class configured only to load the URL the seller // needs. std::unique_ptr<AuctionURLLoaderFactoryProxy> seller_url_loader_factory_; @@ -252,7 +270,6 @@ // 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<GURL> seller_report_url_;
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc index 88fee1d..e864d86 100644 --- a/content/browser/interest_group/auction_runner_unittest.cc +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -246,7 +246,10 @@ : 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)) {} + receiver_(this, std::move(pending_receiver)) { + receiver_.set_disconnect_handler(base::BindOnce( + &MockBidderWorklet::OnPipeClosed, base::Unretained(this))); + } MockBidderWorklet(const MockBidderWorklet&) = delete; const MockBidderWorklet& operator=(const MockBidderWorklet&) = delete; @@ -315,11 +318,21 @@ return url_loader_factory_; } + // Flush the receiver pipe and return whether or not its closed. + bool PipeIsClosed() { + receiver_.FlushForTesting(); + return pipe_closed_; + } + private: + void OnPipeClosed() { pipe_closed_ = true; } + auction_worklet::mojom::AuctionWorkletService:: LoadBidderWorkletAndGenerateBidCallback load_bidder_worklet_and_generate_bid_callback_; + bool pipe_closed_ = false; + std::unique_ptr<base::RunLoop> report_win_run_loop_; ReportWinCallback report_win_callback_; @@ -442,6 +455,8 @@ return url_loader_factory_; } + void Flush() { receiver_.FlushForTesting(); } + private: auction_worklet::mojom::AuctionWorkletService::LoadSellerWorkletCallback load_worklet_callback_; @@ -2117,5 +2132,170 @@ mock_worklet_service_.reset(); } +// Check that BidderWorklets that don't make a bid are destroyed immediately. +TEST_F(AuctionRunnerTest, DestroyBidderWorkletWithoutBid) { + 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->CompleteLoadingWithoutBid(); + // Need to flush the service pipe to make sure the AuctionRunner has received + // the bid. + mock_worklet_service_->Flush(); + // The AuctionRunner should have closed the pipe. + EXPECT_TRUE(bidder1_worklet->PipeIsClosed()); + + // Bidder2 returns a bid, which is then scored. + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad2.com/")); + 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 /* 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_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(5, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(6, result_.bidder2_bid_count); + ASSERT_EQ(4u, result_.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + result_.bidder2_prev_wins[3]->ad_json); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// Check that BidderWorklets are destroyed as soon as there's a higher bid. The +// first BidderWorklet to have its bid scored is the one that loses the auction. +TEST_F(AuctionRunnerTest, DestroyLosingBidderWorkletFirstBidderLoses) { + 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 returns a bid, which is then scored. + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad1.com/")); + 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 */); + // Need to flush the service pipe to make sure the AuctionRunner has received + // the score. + mock_worklet_service_->Flush(); + // The AuctionRunner should not have closed the bidder pipe, since it could + // still be the winning bid. + EXPECT_FALSE(bidder1_worklet->PipeIsClosed()); + + // Bidder2 returns a bid, which is then scored. + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad2.com/")); + 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 */); + // Need to flush the service pipe to make sure the AuctionRunner has received + // the score. + seller_worklet->Flush(); + // The losing bidder should now be destroyed. + EXPECT_TRUE(bidder1_worklet->PipeIsClosed()); + + // 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_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(6, result_.bidder1_bid_count); + EXPECT_EQ(3u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(6, result_.bidder2_bid_count); + ASSERT_EQ(4u, result_.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad2.com/"})", + result_.bidder2_prev_wins[3]->ad_json); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + +// Check that BidderWorklets are destroyed as soon as there's a higher bid. The +// last BidderWorklet to have its bid scored is the one that loses the auction. +TEST_F(AuctionRunnerTest, DestroyLosingBidderWorkletLastBidderLoses) { + 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 returns a bid, which is then scored. + bidder1_worklet->CompleteLoadingAndBid(5 /* bid */, GURL("https://ad1.com/")); + 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(11 /* score */); + + // Bidder2 returns a bid, which is then scored. + bidder2_worklet->CompleteLoadingAndBid(7 /* bid */, GURL("https://ad2.com/")); + 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(10 /* score */); + // Need to flush the service pipe to make sure the AuctionRunner has received + // the score. + seller_worklet->Flush(); + // The losing bidder should now be destroyed. + EXPECT_TRUE(bidder2_worklet->PipeIsClosed()); + + // Finish the auction. + seller_worklet->WaitForReportResult(); + seller_worklet->InvokeReportResultCallback(); + bidder1_worklet->WaitForReportWin(); + bidder1_worklet->InvokeReportWinCallback(); + auction_run_loop_->Run(); + + // Bidder1 won. + EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_url); + EXPECT_FALSE(result_.seller_report_url); + EXPECT_FALSE(result_.bidder_report_url); + EXPECT_EQ(6, result_.bidder1_bid_count); + ASSERT_EQ(4u, result_.bidder1_prev_wins.size()); + EXPECT_EQ(6, result_.bidder2_bid_count); + EXPECT_EQ(3u, result_.bidder2_prev_wins.size()); + EXPECT_EQ(R"({"render_url":"https://ad1.com/","metadata":{"ads": true}})", + result_.bidder1_prev_wins[3]->ad_json); + EXPECT_THAT(result_.errors, testing::ElementsAre()); +} + } // namespace } // namespace content
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index 38425bd..bc2c7d9 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -1716,242 +1716,10 @@ .spec()))); } -// These tests exercise the interest group and ad auction services directly, +// This test exercises the interest group and ad auction services directly, // rather than via Blink, to ensure that those services running in the browser // implement important security checks (Blink may also perform its own // checking, but the render process is untrusted). - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupBasicBypassBlink) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_a; - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(1, GetJoinCount(test_origin_a, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupOriginNotHttps) { - // JS API is https-only, but a compromised renderer could send a http origin. - GURL test_url_http = embedded_test_server()->GetURL("a.test", "/echo"); - url::Origin test_origin_http = url::Origin::Create(test_url_http); - ASSERT_TRUE(test_url_http.SchemeIs(url::kHttpScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_http)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the frame origin isn't https. - auto interest_group_http = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group_http->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group_http->name = kGroupName; - interest_group_http->owner = test_origin_http; - interest_service->JoinInterestGroup(std::move(interest_group_http)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_http, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupWrongOwnerOrigin) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - GURL test_url_b = https_server_->GetURL("b.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - url::Origin test_origin_b = url::Origin::Create(test_url_b); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_b.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the owner origin doesn't match the frame origin. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_b; - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_b, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupWrongBiddingUrlOrigin) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - GURL test_url_b = https_server_->GetURL("b.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - url::Origin test_origin_b = url::Origin::Create(test_url_b); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_b.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the bidding URL origin doesn't match the frame - // origin. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_a; - interest_group->bidding_url = test_url_b; - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_a, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupWrongUpdateUrlOrigin) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - GURL test_url_b = https_server_->GetURL("b.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - url::Origin test_origin_b = url::Origin::Create(test_url_b); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_b.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the update URL origin doesn't match the frame - // origin. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_a; - interest_group->update_url = test_url_b; - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_a, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupWrongTrustedBiddingSignalsOrigin) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - GURL test_url_b = https_server_->GetURL("b.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - url::Origin test_origin_b = url::Origin::Create(test_url_b); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_b.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the trusted bidding signals URL origin doesn't - // match the frame origin. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_a; - interest_group->trusted_bidding_signals_url = test_url_b; - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_a, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - JoinInterestGroupAdRenderingUrlNotHttps) { - GURL test_url_https = https_server_->GetURL("a.test", "/echo"); - GURL test_url_http = embedded_test_server()->GetURL("b.test", "/echo"); - url::Origin test_origin_https = url::Origin::Create(test_url_https); - ASSERT_TRUE(test_url_https.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_http.SchemeIs(url::kHttpScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_https)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service.BindNewPipeAndPassReceiver()); - - // Silently fails to join -- the ad renderingUrl doesn't use https. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_https; - auto ad = blink::mojom::InterestGroupAd::New(); - ad->render_url = test_url_http; - interest_group->ads.emplace(); - interest_group->ads->push_back(std::move(ad)); - interest_service->JoinInterestGroup(std::move(interest_group)); - interest_service.FlushForTesting(); - EXPECT_EQ(0, GetJoinCount(test_origin_https, kGroupName)); -} - -IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, - LeaveInterestGroupWrongOwnerOrigin) { - GURL test_url_a = https_server_->GetURL("a.test", "/echo"); - GURL test_url_b = https_server_->GetURL("b.test", "/echo"); - url::Origin test_origin_a = url::Origin::Create(test_url_a); - url::Origin test_origin_b = url::Origin::Create(test_url_b); - ASSERT_TRUE(test_url_a.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(test_url_b.SchemeIs(url::kHttpsScheme)); - ASSERT_TRUE(NavigateToURL(shell(), test_url_a)); - - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service1; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service1.BindNewPipeAndPassReceiver()); - - // Join succeeds. - auto interest_group = blink::mojom::InterestGroup::New(); - constexpr char kGroupName[] = "cars"; - interest_group->expiry = - base::Time::Now() + base::TimeDelta::FromSeconds(300); - interest_group->name = kGroupName; - interest_group->owner = test_origin_a; - interest_service1->JoinInterestGroup(std::move(interest_group)); - interest_service1.FlushForTesting(); - EXPECT_EQ(1, GetJoinCount(test_origin_a, kGroupName)); - - ASSERT_TRUE(NavigateToURL(shell(), test_url_b)); - // The frame changes upon navigation -- connect to the new service. - mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service2; - InterestGroupServiceImpl::CreateMojoService( - shell()->web_contents()->GetMainFrame(), - interest_service2.BindNewPipeAndPassReceiver()); - - // Silently fails to leave -- the owner origin doesn't match the frame origin. - interest_service2->LeaveInterestGroup(test_origin_a, kGroupName); - interest_service2.FlushForTesting(); - EXPECT_EQ(1, GetJoinCount(test_origin_a, kGroupName)); -} - IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionBasicBypassBlink) { ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL("/echo")));
diff --git a/content/browser/interest_group/interest_group_service_impl.cc b/content/browser/interest_group/interest_group_service_impl.cc index 13a37fc8..a22dc6a 100644 --- a/content/browser/interest_group/interest_group_service_impl.cc +++ b/content/browser/interest_group/interest_group_service_impl.cc
@@ -16,6 +16,27 @@ constexpr base::TimeDelta kMaxExpiry = base::TimeDelta::FromDays(30); +// Check if `url` can be used as an interest group's ad render URL. Ad URLs can +// be cross origin, unlike other interest group URLs, but are still restricted +// to HTTPS with no reference or embedded credentials. +bool IsUrlAllowedForRenderUrls(const GURL& url) { + if (url.scheme() != url::kHttpsScheme) + return false; + + return !url.has_ref() && !url.has_username() && !url.has_password(); +} + +// Check if `url` can be used with the specified interest group for any of +// script URL, update URL, or realtime data URL. Ad render URLs should be +// checked with IsUrlAllowedForRenderUrls(), which doesn't have the same-origin +// check. +bool IsUrlAllowed(const GURL& url, const blink::mojom::InterestGroup& group) { + if (url::Origin::Create(url) != group.owner) + return false; + + return IsUrlAllowedForRenderUrls(url); +} + } // namespace InterestGroupServiceImpl::InterestGroupServiceImpl( @@ -51,27 +72,33 @@ // to devtools to get a better error debugging experience. if (origin().scheme() != url::kHttpsScheme) return; + if (group->owner != origin()) return; - if (group->bidding_url && - url::Origin::Create(*group->bidding_url) != origin()) { + + if (group->bidding_url && !IsUrlAllowed(*group->bidding_url, *group)) return; - } - if (group->update_url && - url::Origin::Create(*group->update_url) != origin()) { + + if (group->update_url && !IsUrlAllowed(*group->update_url, *group)) return; + + if (group->trusted_bidding_signals_url) { + if (!IsUrlAllowed(*group->trusted_bidding_signals_url, *group)) + return; + + // `trusted_bidding_signals_url` must not have a query string, since the + // query parameter needs to be set as part of running an auction. + if (group->trusted_bidding_signals_url->has_query()) + return; } - if (group->trusted_bidding_signals_url && - url::Origin::Create(*group->trusted_bidding_signals_url) != origin()) { - return; - } + if (group->ads) { for (const auto& ad : group->ads.value()) { - if (!ad->render_url.SchemeIs(url::kHttpsScheme)) { + if (!IsUrlAllowedForRenderUrls(ad->render_url)) return; - } } } + base::Time max_expiry = base::Time::Now() + kMaxExpiry; if (group->expiry > max_expiry) group->expiry = max_expiry; @@ -86,12 +113,12 @@ return; } - if (origin().scheme() != url::kHttpsScheme) { + if (origin().scheme() != url::kHttpsScheme) return; - } - if (owner != origin()) { + + if (owner != origin()) return; - } + interest_group_manager_.LeaveInterestGroup(owner, name); }
diff --git a/content/browser/interest_group/interest_group_service_impl_unittest.cc b/content/browser/interest_group/interest_group_service_impl_unittest.cc new file mode 100644 index 0000000..0264a11 --- /dev/null +++ b/content/browser/interest_group/interest_group_service_impl_unittest.cc
@@ -0,0 +1,356 @@ +// 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/interest_group_service_impl.h" + +#include <memory> +#include <string> + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/common/content_client.h" +#include "content/public/test/test_renderer_host.h" +#include "content/test/test_content_browser_client.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h" +#include "third_party/blink/public/mojom/interest_group/restricted_interest_group_store.mojom.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace content { + +namespace { + +const char kInterestGroupName[] = "interest-group-name"; + +class AllowInterestGroupContentBrowserClient : public TestContentBrowserClient { + public: + explicit AllowInterestGroupContentBrowserClient() = default; + ~AllowInterestGroupContentBrowserClient() override = default; + + AllowInterestGroupContentBrowserClient( + const AllowInterestGroupContentBrowserClient&) = delete; + AllowInterestGroupContentBrowserClient& operator=( + const AllowInterestGroupContentBrowserClient&) = delete; + + // ContentBrowserClient overrides: + bool IsInterestGroupAPIAllowed(content::BrowserContext* browser_context, + const url::Origin& top_frame_origin, + const GURL& api_url) override { + return top_frame_origin.host() == "a.test" || + top_frame_origin.host() == "b.test"; + } +}; + +} // namespace + +class InterestGroupServiceTest : public RenderViewHostTestHarness { + public: + InterestGroupServiceTest() { + feature_list_.InitAndEnableFeature(blink::features::kFledgeInterestGroups); + old_content_browser_client_ = + SetBrowserClientForTesting(&content_browser_client_); + } + + ~InterestGroupServiceTest() override { + SetBrowserClientForTesting(old_content_browser_client_); + } + + void SetUp() override { + RenderViewHostTestHarness::SetUp(); + NavigateAndCommit(kUrlA); + + storage_ = (static_cast<StoragePartitionImpl*>( + browser_context()->GetDefaultStoragePartition())) + ->GetInterestGroupStorage(); + } + + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + GetInterestGroupsForOwner(const url::Origin& owner) { + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + interest_groups; + base::RunLoop run_loop; + storage_->GetInterestGroupsForOwner( + owner, + base::BindLambdaForTesting( + [&run_loop, &interest_groups]( + std::vector<auction_worklet::mojom::BiddingInterestGroupPtr> + groups) { + interest_groups = std::move(groups); + run_loop.Quit(); + })); + run_loop.Run(); + return interest_groups; + } + + int GetJoinCount(const url::Origin& owner, const std::string& name) { + for (const auto& interest_group : GetInterestGroupsForOwner(owner)) { + if (interest_group->group->name == name) { + return interest_group->signals->join_count; + } + } + return 0; + } + + // Create a new InterestGroupServiceImpl and use it to try and join + // `interest_group`. Flushes the Mojo pipe to force the Mojo message to be + // handled before returning. + // + // Creates a new InterestGroupServiceImpl with each call so the RFH can be + // navigated between different sites. And InterestGroupServiceImpl only + // handles one site (cross site navs use different InterestGroupServiceImpls, + // and generally use different RFHs as well). + void JoinInterestGroupAndFlush( + blink::mojom::InterestGroupPtr interest_group) { + mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; + InterestGroupServiceImpl::CreateMojoService( + web_contents()->GetMainFrame(), + interest_service.BindNewPipeAndPassReceiver()); + + interest_service->JoinInterestGroup(std::move(interest_group)); + interest_service.FlushForTesting(); + } + + // Analogous to JoinInterestGroupAndFlush(), but leaves an interest group + // instead of joining one. + void LeaveInterestGroupAndFlush(const url::Origin& owner, + const std::string& name) { + mojo::Remote<blink::mojom::RestrictedInterestGroupStore> interest_service; + InterestGroupServiceImpl::CreateMojoService( + web_contents()->GetMainFrame(), + interest_service.BindNewPipeAndPassReceiver()); + + interest_service->LeaveInterestGroup(owner, name); + interest_service.FlushForTesting(); + } + + // Helper to create a valid interest group with only an origin and name. All + // URLs are nullopt. + blink::mojom::InterestGroupPtr CreateInterestGroup() { + auto interest_group = blink::mojom::InterestGroup::New(); + interest_group->expiry = + base::Time::Now() + base::TimeDelta::FromSeconds(300); + interest_group->name = kInterestGroupName; + interest_group->owner = kOriginA; + return interest_group; + } + + protected: + const GURL kUrlA = GURL("https://a.test/"); + const url::Origin kOriginA = url::Origin::Create(kUrlA); + const GURL kUrlB = GURL("https://b.test/"); + const url::Origin kOriginB = url::Origin::Create(kUrlB); + + base::test::ScopedFeatureList feature_list_; + + AllowInterestGroupContentBrowserClient content_browser_client_; + ContentBrowserClient* old_content_browser_client_ = nullptr; + InterestGroupManager* storage_; +}; + +// Check basic success case. +TEST_F(InterestGroupServiceTest, JoinInterestGroupBasic) { + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName)); + + // Several tests assume interest group API are also allowed on kOriginB, so + // make sure that's enabled correctly. + NavigateAndCommit(kUrlB); + interest_group = CreateInterestGroup(); + interest_group->owner = kOriginB; + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(1, GetJoinCount(kOriginB, kInterestGroupName)); +} + +// Non-HTTPS interest groups should be rejected. +TEST_F(InterestGroupServiceTest, JoinInterestGroupOriginNotHttps) { + // Note that the ContentBrowserClient allows URLs based on hosts, not origins, + // so it should not block this URL. Instead, it should run into the HTTPS + // check. + const GURL kHttpUrlA = GURL("http://a.test/"); + const url::Origin kHttpOriginA = url::Origin::Create(kHttpUrlA); + NavigateAndCommit(kHttpUrlA); + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + interest_group->owner = kHttpOriginA; + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(0, GetJoinCount(kHttpOriginA, kInterestGroupName)); +} + +// Test one origin trying to add an interest group for another. +TEST_F(InterestGroupServiceTest, JoinInterestGroupWrongOwnerOrigin) { + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + interest_group->owner = kOriginB; + JoinInterestGroupAndFlush(std::move(interest_group)); + // Interest group should not be added for either origin. + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); + EXPECT_EQ(0, GetJoinCount(kOriginB, kInterestGroupName)); +} + +// Check that `bidding_url`, `update_url`, and `trusted_bidding_signals_url` +// must be same-origin and HTTPS. +// +// Ad URLs do not have to be same origin, so they're checked in a different +// test. +TEST_F(InterestGroupServiceTest, JoinInterestGroupUrlValidation) { + // Nested URL schemes, like filesystem URLs, are the only cases where a URL + // being same origin with an HTTPS origin does not imply the URL itself is + // also HTTPS. + const GURL kFileSystemUrl = GURL("filesystem:https://a.test/foo"); + EXPECT_EQ(kOriginA, url::Origin::Create(kFileSystemUrl)); + + const GURL kRejectedUrls[] = { + // HTTP URLs are rejected: They're both the wrong scheme, and + // cross-origin. + GURL("http://a.test/"), + // Cross origin URLs are rejected. + GURL("https://b.test/"), + // URL with different ports are cross-origin. + GURL("https://a.test:1234/"), + // URLs with opaque origins are cross-origin. + GURL("data://text/html,payload"), + + // filesystem URLs are rejected, even if they're same-origin with the page + // origin. + kFileSystemUrl, + + // URLs with user/ports are rejected. + GURL("https://user:pass@a.test/"), + // References also aren't allowed, as they aren't sent over HTTP. + GURL("https://a.test/#foopy"), + }; + + for (const GURL& rejected_url : kRejectedUrls) { + SCOPED_TRACE(rejected_url.spec()); + + // Test `bidding_url`. + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + interest_group->bidding_url = rejected_url; + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); + + // Test `update_url`. + interest_group = CreateInterestGroup(); + interest_group->update_url = rejected_url; + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); + + // Test `trusted_bidding_signals_url`. + interest_group = CreateInterestGroup(); + interest_group->trusted_bidding_signals_url = rejected_url; + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); + } + + // `trusted_bidding_signals_url` also can't include query strings. + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + interest_group->trusted_bidding_signals_url = GURL("https://a.test/?query"); + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); + + // Test success case for each field. + + // Test `bidding_url`. + interest_group = CreateInterestGroup(); + interest_group->bidding_url = GURL("https://a.test/foo/bar.js?query"); + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName)); + + // Test `update_url`. + interest_group = CreateInterestGroup(); + interest_group->update_url = GURL("https://a.test/foo/bar.js?query"); + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(2, GetJoinCount(kOriginA, kInterestGroupName)); + + // Test `trusted_bidding_signals_url`. + interest_group = CreateInterestGroup(); + interest_group->trusted_bidding_signals_url = + GURL("https://a.test/foo/bar.js"); + JoinInterestGroupAndFlush(std::move(interest_group)); + EXPECT_EQ(3, GetJoinCount(kOriginA, kInterestGroupName)); +} + +TEST_F(InterestGroupServiceTest, JoinInterestGroupAdUrlValidation) { + const struct { + bool expect_allowed; + GURL url; + } kTestCases[] = { + // Same origin URLs are allowed. + {true, GURL("https://a.test:1234/foo")}, + + // Cross origin URLs are allowed, as long as they're HTTPS. + {true, GURL("https://b.test/")}, + {true, GURL("https://a.test:1234/")}, + + // URLs with the wrong scheme are rejected. + {false, GURL("http://a.test/")}, + {false, GURL("data://text/html,payload")}, + {false, GURL("filesystem:https://a.test/foo")}, + + // URLs with user/ports are rejected. + {false, GURL("https://user:pass@a.test/")}, + + // References also aren't allowed, as they aren't sent over HTTP. + {false, GURL("https://a.test/#foopy")}, + }; + + for (const auto& test_case : kTestCases) { + SCOPED_TRACE(test_case.url.spec()); + + // Add an InterestGroup with the test cases's URL as the only ad's URL. + int initial_join_count = GetJoinCount(kOriginA, kInterestGroupName); + blink::mojom::InterestGroupPtr interest_group = CreateInterestGroup(); + interest_group->ads.emplace(); + interest_group->ads->emplace_back(blink::mojom::InterestGroupAd::New( + test_case.url, absl::nullopt /* metadata */)); + JoinInterestGroupAndFlush(std::move(interest_group)); + if (test_case.expect_allowed) { + EXPECT_EQ(initial_join_count + 1, + GetJoinCount(kOriginA, kInterestGroupName)); + } else { + EXPECT_EQ(initial_join_count, GetJoinCount(kOriginA, kInterestGroupName)); + } + + // Add an InterestGroup with the test cases's URL as the second ad's URL. + initial_join_count = GetJoinCount(kOriginA, kInterestGroupName); + interest_group = CreateInterestGroup(); + interest_group->ads.emplace(); + interest_group->ads->emplace_back(blink::mojom::InterestGroupAd::New( + GURL("https://a.test/"), absl::nullopt /* metadata */)); + interest_group->ads->emplace_back(blink::mojom::InterestGroupAd::New( + test_case.url, absl::nullopt /* metadata */)); + JoinInterestGroupAndFlush(std::move(interest_group)); + if (test_case.expect_allowed) { + EXPECT_EQ(initial_join_count + 1, + GetJoinCount(kOriginA, kInterestGroupName)); + } else { + EXPECT_EQ(initial_join_count, GetJoinCount(kOriginA, kInterestGroupName)); + } + } +} + +// Check that cross-origin leave interest group operations don't work. +TEST_F(InterestGroupServiceTest, LeaveInterestGroupWrongOwnerOrigin) { + // https://a.test/ joins an interest group. + JoinInterestGroupAndFlush(CreateInterestGroup()); + EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName)); + + // https://b.test/ cannot leave https://a.test/'s interest group. + NavigateAndCommit(kUrlB); + LeaveInterestGroupAndFlush(kOriginA, kInterestGroupName); + EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName)); + + // https://a.test/ can leave its own the interest group. + NavigateAndCommit(GURL("https://a.test/")); + LeaveInterestGroupAndFlush(kOriginA, kInterestGroupName); + EXPECT_EQ(0, GetJoinCount(kOriginA, kInterestGroupName)); +} + +} // namespace content
diff --git a/content/browser/native_io/native_io_quota_client.h b/content/browser/native_io/native_io_quota_client.h index b3fccb7f..2b3b57d 100644 --- a/content/browser/native_io/native_io_quota_client.h +++ b/content/browser/native_io/native_io_quota_client.h
@@ -6,7 +6,7 @@ #define CONTENT_BROWSER_NATIVE_IO_NATIVE_IO_QUOTA_CLIENT_H_ #include "base/sequence_checker.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" +#include "components/services/storage/public/cpp/origin_quota_client.h" #include "content/common/content_export.h" #include "storage/browser/quota/quota_client_type.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" @@ -19,7 +19,7 @@ // Integrates NativeIO with the quota system. // // Each NativeIOManager owns exactly one NativeIOQuotaClient. -class CONTENT_EXPORT NativeIOQuotaClient : public storage::mojom::QuotaClient { +class CONTENT_EXPORT NativeIOQuotaClient : public storage::OriginQuotaClient { public: explicit NativeIOQuotaClient(NativeIOManager* manager); ~NativeIOQuotaClient() override; @@ -27,7 +27,7 @@ NativeIOQuotaClient(const NativeIOQuotaClient&) = delete; NativeIOQuotaClient& operator=(const NativeIOQuotaClient&) = delete; - // QuotaClient. + // storage::OriginQuotaClient method overrides. void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, GetOriginUsageCallback callback) override;
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc index e10134a..f9c85a8 100644 --- a/content/browser/push_messaging/push_messaging_router.cc +++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -179,7 +179,7 @@ if (payload) event_metadata["Payload"] = *payload; devtools_context->LogBackgroundServiceEventOnCoreThread( - service_worker->registration_id(), service_worker->origin(), + service_worker->registration_id(), service_worker->key().origin(), DevToolsBackgroundService::kPushMessaging, "Push event dispatched", message_id, event_metadata); } @@ -245,7 +245,7 @@ push_event_status != blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR) { devtools_context->LogBackgroundServiceEventOnCoreThread( - service_worker->registration_id(), service_worker->origin(), + service_worker->registration_id(), service_worker->key().origin(), DevToolsBackgroundService::kPushMessaging, "Push event completed", message_id, {{"Status", status_description}}); }
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index ef41602..54821d8 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -913,8 +913,11 @@ std::move(commit_params), browser_initiated, false /* from_begin_navigation */, false /* is_for_commit */, frame_entry, entry, std::move(navigation_ui_data), std::move(blob_url_loader_factory), - mojo::NullAssociatedRemote(), rfh_restored_from_back_forward_cache, - initiator_process_id, was_opener_suppressed)); + mojo::NullAssociatedRemote(), + nullptr /* prefetched_signed_exchange_cache */, + nullptr /* web_bundle_handle_tracker */, + rfh_restored_from_back_forward_cache, initiator_process_id, + was_opener_suppressed)); return navigation_request; } @@ -1014,13 +1017,11 @@ entry, nullptr, // navigation_ui_data std::move(blob_url_loader_factory), std::move(navigation_client), + std::move(prefetched_signed_exchange_cache), + std::move(web_bundle_handle_tracker), nullptr, // rfh_restored_from_back_forward_cache initiator_process_id, /*was_opener_suppressed=*/false)); - navigation_request->prefetched_signed_exchange_cache_ = - std::move(prefetched_signed_exchange_cache); - navigation_request->web_bundle_handle_tracker_ = - std::move(web_bundle_handle_tracker); return navigation_request; } @@ -1123,6 +1124,8 @@ nullptr /* frame_navigation_entry */, nullptr /* navigation_entry */, nullptr /* navigation_ui_data */, nullptr /* blob_url_loader_factory */, mojo::NullAssociatedRemote(), + nullptr /* prefetched_signed_exchange_cache */, + nullptr /* web_bundle_handle_tracker */, nullptr /* rfh_restored_from_back_forward_cache */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, false /* was_opener_suppressed */)); @@ -1163,6 +1166,9 @@ std::unique_ptr<NavigationUIData> navigation_ui_data, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, + scoped_refptr<PrefetchedSignedExchangeCache> + prefetched_signed_exchange_cache, + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, RenderFrameHostImpl* rfh_restored_from_back_forward_cache, int initiator_process_id, bool was_opener_suppressed) @@ -1186,6 +1192,9 @@ navigation_entry_offset_( EstimateHistoryOffset(frame_tree_node_->navigator().controller(), common_params_->should_replace_current_entry)), + prefetched_signed_exchange_cache_( + std::move(prefetched_signed_exchange_cache)), + web_bundle_handle_tracker_(std::move(web_bundle_handle_tracker)), rfh_restored_from_back_forward_cache_( rfh_restored_from_back_forward_cache), // Store the old RenderFrameHost id at request creation to be used later.
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index d63388a..7a78c2d 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h
@@ -911,6 +911,9 @@ std::unique_ptr<NavigationUIData> navigation_ui_data, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, + scoped_refptr<PrefetchedSignedExchangeCache> + prefetched_signed_exchange_cache, + std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker, RenderFrameHostImpl* rfh_restored_from_back_forward_cache, int initiator_process_id, bool was_opener_suppressed); @@ -1530,7 +1533,7 @@ // Tracks navigations within a Web Bundle file. Used when WebBundles feature // is enabled or TrustableWebBundleFileUrl switch is set. - std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker_; + const std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker_; // Timing information of loading for the navigation. Used for recording UMAs. NavigationHandleTiming navigation_handle_timing_;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 7549a07..7eb606f 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -830,15 +830,18 @@ if (renderer_side_origin.opaque() && browser_side_origin.opaque()) return; - // Navigating to file://localhost/... on windows causes `browser_side_origin` - // and `renderer_side_origin` to be different (file://localhost/ vs file:///). - // In particular, without the following block the test +#if defined(OS_WIN) + // TODO(https://crbug.com/1214098): Navigating to a test-crafted + // (GURL::ReplaceComponents-crafted) file://localhost/C:/dir/file.txt URL will + // fail to round-trip the URL causing `browser_side_origin` and + // `renderer_side_origin` to be different (file://localhost/ vs file:///). In + // particular, without the following "if" statement the test // ContentSecurityPolicyBrowserTest.FileURLs fails. - if ((browser_side_origin.opaque() == renderer_side_origin.opaque()) && - browser_side_origin.scheme() == url::kFileScheme && + if (browser_side_origin.scheme() == url::kFileScheme && renderer_side_origin.scheme() == url::kFileScheme) { return; } +#endif DCHECK_EQ(browser_side_origin, renderer_side_origin) << "; navigation_request->GetURL() = " << navigation_request->GetURL();
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index cf913d6e..117e82da 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -48,6 +48,7 @@ #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom.h" #include "third_party/blink/public/mojom/renderer_preference_watcher.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h" @@ -1137,7 +1138,7 @@ return; rph->BindCacheStorage(coep, std::move(coep_reporter_remote), - owner_version_->origin(), std::move(receiver)); + owner_version_->key().origin(), std::move(receiver)); } pending_cache_storage_receivers_.clear(); }
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc index e66da05..dd68eb4 100644 --- a/content/browser/service_worker/service_worker_client_utils.cc +++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -433,10 +433,7 @@ if (options->include_uncontrolled) { if (controller->context()) { for (auto it = controller->context()->GetClientContainerHostIterator( - // TODO(crbug.com/1199077): Update this when ServiceWorkerVersion - // implements StorageKey. - blink::StorageKey(controller->origin()), - false /* include_reserved_clients */, + controller->key(), false /* include_reserved_clients */, false /* include_back_forward_cached_clients */); !it->IsAtEnd(); it->Advance()) { AddNonWindowClient(it->GetContainerHost(), options->client_type, @@ -478,10 +475,7 @@ if (options->include_uncontrolled) { if (controller->context()) { for (auto it = controller->context()->GetClientContainerHostIterator( - // TODO(crbug.com/1199077): Update this when ServiceWorkerVersion - // implements StorageKey. - blink::StorageKey(controller->origin()), - false /* include_reserved_clients */, + controller->key(), false /* include_reserved_clients */, false /* include_back_forward_cached_clients */); !it->IsAtEnd(); it->Advance()) { AddWindowClient(it->GetContainerHost(), &clients_info); @@ -507,6 +501,8 @@ std::move(clients))); } +// TODO(crbug.com/1199077): Update `sane_origin` to StorageKey once +// ServiceWorkerContainerHost implements StorageKey. void DidGetExecutionReadyClient( const base::WeakPtr<ServiceWorkerContextCore>& context, const std::string& client_uuid, @@ -553,6 +549,7 @@ void OpenWindow(const GURL& url, const GURL& script_url, + const blink::StorageKey& key, int worker_id, int worker_process_id, const base::WeakPtr<ServiceWorkerContextCore>& context, @@ -564,12 +561,13 @@ base::BindOnce( &OpenWindowOnUI, url, script_url, worker_id, worker_process_id, base::WrapRefCounted(context->wrapper()), type, - base::BindOnce(&DidNavigate, context, script_url.GetOrigin(), + base::BindOnce(&DidNavigate, context, script_url.GetOrigin(), key, std::move(callback)))); } void NavigateClient(const GURL& url, const GURL& script_url, + const blink::StorageKey& key, int process_id, int frame_id, const base::WeakPtr<ServiceWorkerContextCore>& context, @@ -580,7 +578,7 @@ FROM_HERE, BrowserThread::UI, base::BindOnce( &NavigateClientOnUI, url, script_url, process_id, frame_id, - base::BindOnce(&DidNavigate, context, script_url.GetOrigin(), + base::BindOnce(&DidNavigate, context, script_url.GetOrigin(), key, std::move(callback)))); } @@ -638,6 +636,7 @@ void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, const GURL& origin, + const blink::StorageKey& key, NavigationCallback callback, int render_process_id, int render_frame_id) { @@ -658,10 +657,7 @@ for (std::unique_ptr<ServiceWorkerContextCore::ContainerHostIterator> it = context->GetClientContainerHostIterator( - // TODO(crbug.com/1199077): Update this when ServiceWorkerVersion - // implements StorageKey. - blink::StorageKey(url::Origin::Create(origin)), - true /* include_reserved_clients */, + key, true /* include_reserved_clients */, false /* include_back_forward_cached_clients */); !it->IsAtEnd(); it->Advance()) { ServiceWorkerContainerHost* container_host = it->GetContainerHost();
diff --git a/content/browser/service_worker/service_worker_client_utils.h b/content/browser/service_worker/service_worker_client_utils.h index 2674fde..e156d72 100644 --- a/content/browser/service_worker/service_worker_client_utils.h +++ b/content/browser/service_worker/service_worker_client_utils.h
@@ -13,6 +13,10 @@ class GURL; +namespace blink { +class StorageKey; +} // namespace blink + namespace content { class ServiceWorkerContainerHost; @@ -42,24 +46,26 @@ void FocusWindowClient(ServiceWorkerContainerHost* container_host, ClientCallback callback); -// Opens a new window and navigates it to |url|. |callback| is called with the -// window's client information on completion. If |type| is NEW_TAB_WINDOW, we -// will open a new app window, if there is an app installed that has |url| in +// Opens a new window and navigates it to `url`. `callback` is called with the +// window's client information on completion. If `type` is NEW_TAB_WINDOW, we +// will open a new app window, if there is an app installed that has `url` in // its scope. What an "installed app" is depends on the embedder of content. In // Chrome's case, it is an installed Progressive Web App. If there is no such // app, we will open a new foreground tab instead. void OpenWindow(const GURL& url, const GURL& script_url, + const blink::StorageKey& key, int worker_id, int worker_process_id, const base::WeakPtr<ServiceWorkerContextCore>& context, WindowType type, NavigationCallback callback); -// Navigates the client specified by |process_id| and |frame_id| to |url|. -// |callback| is called with the client information on completion. +// Navigates the client specified by `process_id` and `frame_id` to `url`. +// `callback` is called with the client information on completion. void NavigateClient(const GURL& url, const GURL& script_url, + const blink::StorageKey& key, int process_id, int frame_id, const base::WeakPtr<ServiceWorkerContextCore>& context, @@ -76,12 +82,15 @@ blink::mojom::ServiceWorkerClientQueryOptionsPtr options, blink::mojom::ServiceWorkerHost::GetClientsCallback callback); -// Finds the provider host for |origin| in |context| then uses -// |render_process_id| and |render_process_host| to create a relevant -// blink::mojom::ServiceWorkerClientInfo struct and calls |callback| with it. +// Finds the provider host for `key` in `context` then uses +// `render_process_id` and `render_process_host` to create a relevant +// blink::mojom::ServiceWorkerClientInfo struct and calls `callback` with it. // Must be called on the core thread. +// TODO(crbug.com/1199077): Remove `origin` once DidGetExecutionReadyClient +// implements StorageKey. void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, const GURL& origin, + const blink::StorageKey& key, NavigationCallback callback, int render_process_id, int render_frame_id);
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index e7b77f29..428d514f 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -544,7 +544,7 @@ GetAllLiveVersionInfo(); for (const ServiceWorkerVersionInfo& info : live_version_info) { ServiceWorkerVersion* version = GetLiveVersion(info.version_id); - if (version && version->origin() == origin) { + if (version && version->key().origin() == origin) { return version->GetExternalRequestCountForTest(); // IN-TEST } } @@ -808,7 +808,7 @@ std::vector<ServiceWorkerVersionInfo> live_versions = GetAllLiveVersionInfo(); for (const ServiceWorkerVersionInfo& info : live_versions) { ServiceWorkerVersion* version = GetLiveVersion(info.version_id); - if (version && version->origin() == origin) + if (version && version->key().origin() == origin) version->StopWorker(base::DoNothing()); } }
diff --git a/content/browser/service_worker/service_worker_host.cc b/content/browser/service_worker/service_worker_host.cc index dead583..4a53662 100644 --- a/content/browser/service_worker/service_worker_host.cc +++ b/content/browser/service_worker/service_worker_host.cc
@@ -23,6 +23,7 @@ #include "mojo/public/cpp/bindings/message.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/messaging/message_port_channel.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h" namespace content { @@ -64,7 +65,8 @@ container_host_->set_service_worker_host(this); container_host_->UpdateUrls( version_->script_url(), - net::SiteForCookies::FromUrl(version_->script_url()), version_->origin()); + net::SiteForCookies::FromUrl(version_->script_url()), + version_->key().origin()); } ServiceWorkerHost::~ServiceWorkerHost() { @@ -97,7 +99,7 @@ RunOrPostTaskOnThread( FROM_HERE, BrowserThread::UI, base::BindOnce(&CreateWebTransportConnectorImpl, worker_process_id_, - version_->origin(), GetNetworkIsolationKey(), + version_->key().origin(), GetNetworkIsolationKey(), std::move(receiver))); } @@ -114,7 +116,7 @@ // top-level browsing context, which shouldn't be use for ServiceWorkers used // in iframes. return net::NetworkIsolationKey::ToDoUseTopFrameOriginAsWell( - version_->origin()); + version_->key().origin()); } const base::UnguessableToken& ServiceWorkerHost::GetReportingSource() const {
diff --git a/content/browser/service_worker/service_worker_new_script_fetcher.cc b/content/browser/service_worker/service_worker_new_script_fetcher.cc index e0426de..157e8b9 100644 --- a/content/browser/service_worker/service_worker_new_script_fetcher.cc +++ b/content/browser/service_worker/service_worker_new_script_fetcher.cc
@@ -10,6 +10,7 @@ #include "content/public/browser/global_request_id.h" #include "mojo/public/cpp/system/data_pipe_utils.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" namespace content { @@ -90,9 +91,9 @@ } network::ResourceRequest request = service_worker_loader_helpers::CreateRequestForServiceWorkerScript( - version_->script_url(), version_->origin(), /*is_main_script=*/true, - version_->script_type(), *fetch_client_settings_object_, - *browser_context); + version_->script_url(), version_->key().origin(), + /*is_main_script=*/true, version_->script_type(), + *fetch_client_settings_object_, *browser_context); // Request SSLInfo. It will be persisted in service worker storage and may be // used by ServiceWorkerMainResourceLoader for navigations handled by this // service worker.
diff --git a/content/browser/service_worker/service_worker_quota_client.h b/content/browser/service_worker/service_worker_quota_client.h index 60b50a64..315a540c 100644 --- a/content/browser/service_worker/service_worker_quota_client.h +++ b/content/browser/service_worker/service_worker_quota_client.h
@@ -10,7 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" -#include "components/services/storage/public/mojom/quota_client.mojom.h" +#include "components/services/storage/public/cpp/origin_quota_client.h" #include "content/common/content_export.h" #include "storage/browser/quota/quota_client_type.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" @@ -22,7 +22,7 @@ namespace content { class ServiceWorkerContextCore; -class ServiceWorkerQuotaClient : public storage::mojom::QuotaClient { +class ServiceWorkerQuotaClient : public storage::OriginQuotaClient { public: // `context` must outlive this instance. This is true because `context` owns // this instance. @@ -40,7 +40,7 @@ context_ = &new_context; } - // storage::mojom::QuotaClient: + // storage::OriginQuotaClient override methods. void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, GetOriginUsageCallback callback) override;
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index 62cd2b18..0197da4a 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -784,9 +784,9 @@ protected: void SetUp() override { ServiceWorkerRegistrationTest::SetUp(); - mojo::SetDefaultProcessErrorHandler(base::AdaptCallbackForRepeating( - base::BindOnce(&ServiceWorkerRegistrationObjectHostTest::OnMojoError, - base::Unretained(this)))); + mojo::SetDefaultProcessErrorHandler(base::BindRepeating( + &ServiceWorkerRegistrationObjectHostTest::OnMojoError, + base::Unretained(this))); } void TearDown() override {
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc index 6237fa5e..cc870bf 100644 --- a/content/browser/service_worker/service_worker_registry.cc +++ b/content/browser/service_worker/service_worker_registry.cc
@@ -173,6 +173,8 @@ std::move(callback))); } +// TODO(http://crbug.com/1199077): This function doesn't need to take in a +// StorageKey, it can get it from ServiceWorkerRegistration. Clean up. void ServiceWorkerRegistry::CreateNewVersion( scoped_refptr<ServiceWorkerRegistration> registration, const GURL& script_url,
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc index 13ac2aa..5022aa5 100644 --- a/content/browser/service_worker/service_worker_test_utils.cc +++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -385,8 +385,6 @@ return registration; } -// TODO(http://crbug.com/1199077): Update after ServiceWorkerVersion supports -// StorageKey. scoped_refptr<ServiceWorkerVersion> CreateNewServiceWorkerVersion( ServiceWorkerRegistry* registry, scoped_refptr<ServiceWorkerRegistration> registration,
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 561ca59..907cc25 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -161,6 +161,7 @@ void DidShowPaymentHandlerWindow( const GURL& url, + const blink::StorageKey& key, const base::WeakPtr<ServiceWorkerContextCore>& context, blink::mojom::ServiceWorkerHost::OpenPaymentHandlerWindowCallback callback, bool success, @@ -168,7 +169,7 @@ int render_frame_id) { if (success) { service_worker_client_utils::DidNavigate( - context, url.GetOrigin(), + context, url.GetOrigin(), key, base::BindOnce(&OnOpenWindowFinished, std::move(callback)), render_process_id, render_frame_id); } else { @@ -244,7 +245,7 @@ : version_id_(version_id), registration_id_(registration->id()), script_url_(script_url), - origin_(registration->key().origin()), + key_(registration->key()), scope_(registration->scope()), script_type_(script_type), fetch_handler_existence_(FetchHandlerExistence::UNKNOWN), @@ -384,7 +385,7 @@ DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); ServiceWorkerVersionInfo info( running_status(), status(), fetch_handler_existence(), script_url(), - scope(), origin(), registration_id(), version_id(), + scope(), key().origin(), registration_id(), version_id(), embedded_worker()->process_id(), embedded_worker()->thread_id(), embedded_worker()->worker_devtools_agent_route_id(), ukm_source_id()); for (const auto& controllee : controllee_map_) { @@ -467,7 +468,7 @@ // get associated with it in // ServiceWorkerHost::CompleteStartWorkerPreparation. context_->registry()->FindRegistrationForId( - registration_id_, blink::StorageKey(origin_), + registration_id_, key_, base::BindOnce( &ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker, weak_factory_.GetWeakPtr(), purpose, status_, @@ -585,7 +586,7 @@ if (!context_) return; context_->registry()->FindRegistrationForId( - registration_id_, blink::StorageKey(origin_), + registration_id_, key_, base::BindOnce(&ServiceWorkerVersion::FoundRegistrationForUpdate, weak_factory_.GetWeakPtr())); } @@ -1398,6 +1399,8 @@ void ServiceWorkerVersion::OpenNewTab(const GURL& url, OpenNewTabCallback callback) { + // TODO(crbug.com/1199077): After StorageKey implements partitioning update + // this to reject with InvalidAccessError if key_ is partitioned. OpenWindow(url, service_worker_client_utils::WindowType::NEW_TAB_WINDOW, std::move(callback)); } @@ -1413,7 +1416,8 @@ return; } - if (!url.is_valid() || !url::Origin::Create(url).IsSameOriginWith(origin_)) { + if (!url.is_valid() || + !url::Origin::Create(url).IsSameOriginWith(key_.origin())) { mojo::ReportBadMessage( "Received PaymentRequestEvent#openWindow() request for a cross-origin " "URL."); @@ -1423,7 +1427,7 @@ PaymentHandlerSupport::ShowPaymentHandlerWindow( url, context_.get(), - base::BindOnce(&DidShowPaymentHandlerWindow, url, context_), + base::BindOnce(&DidShowPaymentHandlerWindow, url, key_, context_), base::BindOnce( &ServiceWorkerVersion::OpenWindow, weak_factory_.GetWeakPtr(), url, service_worker_client_utils::WindowType::PAYMENT_HANDLER_WINDOW), @@ -1579,7 +1583,7 @@ } service_worker_client_utils::NavigateClient( - url, script_url_, container_host->process_id(), + url, script_url_, key_, container_host->process_id(), container_host->frame_id(), context_, base::BindOnce(&DidNavigateClient, std::move(callback), url)); } @@ -1675,7 +1679,7 @@ } service_worker_client_utils::OpenWindow( - url, script_url_, embedded_worker_->embedded_worker_id(), + url, script_url_, key_, embedded_worker_->embedded_worker_id(), embedded_worker_->process_id(), context_, type, base::BindOnce(&OnOpenWindowFinished, std::move(callback))); }
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 3804f76e..baf2b913 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -52,6 +52,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/origin_trials/trial_token_validator.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h" #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h" @@ -204,7 +205,7 @@ int64_t version_id() const { return version_id_; } int64_t registration_id() const { return registration_id_; } const GURL& script_url() const { return script_url_; } - const url::Origin& origin() const { return origin_; } + const blink::StorageKey& key() const { return key_; } const GURL& scope() const { return scope_; } blink::mojom::ScriptType script_type() const { return script_type_; } EmbeddedWorkerStatus running_status() const { @@ -915,10 +916,10 @@ const int64_t version_id_; const int64_t registration_id_; const GURL script_url_; - // |origin_| is computed from |scope_|. Warning: The |script_url_|'s origin - // and |origin_| may be different in some scenarios e.g. + // `key_` is computed from `scope_`. Warning: The `script_url_`'s origin + // and `key_` may be different in some scenarios e.g. // --disable-web-security. - const url::Origin origin_; + const blink::StorageKey key_; const GURL scope_; // A service worker has an associated type which is either // "classic" or "module". Unless stated otherwise, it is "classic".
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index bf16205..15f1c48 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -102,7 +102,7 @@ helper_->context()->registry(), registration_.get(), GURL("https://www.example.com/test/service_worker.js"), blink::mojom::ScriptType::kClassic); - EXPECT_EQ(url::Origin::Create(scope_), version_->origin()); + EXPECT_EQ(url::Origin::Create(scope_), version_->key().origin()); std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> records; records.push_back(WriteToDiskCacheWithIdSync( helper_->context()->GetStorageControl(), version_->script_url(), 10,
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc index 44c9db4..e02f2840 100644 --- a/content/browser/tracing/startup_tracing_browsertest.cc +++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -337,7 +337,9 @@ testing::Values(OutputLocation::kDirectoryWithDefaultBasename))); // TODO(crbug.com/1197278): Failing on Windows 7 debug builds. -#if defined(OS_WIN) && DCHECK_IS_ON() +// TODO(crbug.com/1211717): Failing on Linux TSAN builds. +#if (defined(OS_WIN) && DCHECK_IS_ON()) || \ + (defined(OS_LINUX) && defined(THREAD_SANITIZER)) #define MAYBE_StopOnUIThread DISABLED_StopOnUIThread #else #define MAYBE_StopOnUIThread StopOnUIThread
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 841b1e2..850bd0e 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1860,6 +1860,85 @@ EXPECT_EQ("1\n2\n3\n4", test_delegate.last_message()); } +class WebContentsImplBrowserTestWithDifferentOriginSubframeDialogSuppression + : public WebContentsImplBrowserTest { + public: + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + features::kSuppressDifferentOriginSubframeJSDialogs); + WebContentsImplBrowserTest::SetUp(); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + WebContentsImplBrowserTestWithDifferentOriginSubframeDialogSuppression, + OriginTrialDisablesSuppression) { + // Generated with tools/origin_trials/generate_token.py --expire-days 5000 + // http://allowdialogs.test:9999 + // DisableDifferentOriginSubframeDialogSuppression + std::string origin_trial_token = + "AwcVbxsLRzn8IXBNaeCrK7amKs211vWkv5oCYo+gssujKeltEtcIaQD+O9hWO+" + "GT3WtKUFhEA30+QuqyU3TUvQkAAAB/" + "eyJvcmlnaW4iOiAiaHR0cDovL2FsbG93ZGlhbG9ncy50ZXN0Ojk5OTkiLCAiZmVhdHVyZSI6" + "ICJEaXNhYmxlRGlmZmVyZW50T3JpZ2luU3ViZnJhbWVEaWFsb2dTdXBwcmVzc2lvbiIsICJl" + "eHBpcnkiOiAyMDU0NzU5MTcyfQ=="; + GURL origin_trial_url = GURL("http://allowdialogs.test:9999"); + + WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); + TestWCDelegateForDialogsAndFullscreen test_delegate(wc); + + ASSERT_TRUE(embedded_test_server()->Start()); + + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); + EXPECT_TRUE(WaitForLoadStop(wc)); + + FrameTreeNode* root = wc->GetFrameTree()->root(); + ASSERT_EQ(0U, root->child_count()); + + std::string script = + "var iframe = document.createElement('iframe');" + "document.body.appendChild(iframe);"; + EXPECT_TRUE(ExecJs(root->current_frame_host(), script)); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + + ASSERT_EQ(1U, root->child_count()); + FrameTreeNode* frame = root->child_at(0); + ASSERT_NE(nullptr, frame); + + // We need to use a URLLoaderInterceptor for the subframe since origin trial + // is origin bound, and embedded test server randomizes ports. + URLLoaderInterceptor interceptor(base::BindLambdaForTesting( + [&](URLLoaderInterceptor::RequestParams* params) { + if (params->url_request.url != origin_trial_url) + return false; + URLLoaderInterceptor::WriteResponse( + "HTTP/1.1 200 OK\n" + "Content-type: text/html\n" + "Origin-Trial: " + + origin_trial_token + "\n\n", + "", params->client.get()); + return true; + })); + + // A dialog from the subframe. + // Navigate the subframe to the site with the origin trial meta tag. + EXPECT_TRUE(NavigateToURLFromRenderer(frame, origin_trial_url)); + EXPECT_TRUE(WaitForLoadStop(wc)); + + // A dialog from the subframe, which should show even though different origin + // subframe dialog suppression is enabled, since the origin trial overrides + // it. + std::string alert_location = "alert(document.location)"; + test_delegate.WillWaitForDialog(); + EXPECT_TRUE(ExecJs(frame->current_frame_host(), alert_location)); + test_delegate.Wait(); + EXPECT_EQ(origin_trial_url, GURL(test_delegate.last_message())); +} + IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, CreateWebContentsWithRendererProcess) { ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index 4e168c7..32dbc4d 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -252,4 +252,8 @@ return absl::nullopt; } +void ContentRendererClient::AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) {} + } // namespace content
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 6016334..bb987f3a 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -50,6 +50,7 @@ class WebServiceWorkerContextProxy; class WebURL; class WebURLRequest; +struct WebContentSecurityPolicyHeader; struct WebPluginParams; struct WebURLError; enum class ProtocolHandlerSecurityLevel; @@ -398,6 +399,12 @@ virtual absl::optional<::media::AudioRendererAlgorithmParameters> GetAudioRendererAlgorithmParameters( ::media::AudioParameters audio_parameters); + + // Appends to `csp`, the default CSP which should be applied to the given + // `url`. This allows the embedder to customize the applied CSP. + virtual void AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp); }; } // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 2b4cf709..5ccc942 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1123,4 +1123,10 @@ return std::make_unique<V8ValueConverterImpl>(); } +void RendererBlinkPlatformImpl::AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) { + GetContentClient()->renderer()->AppendContentSecurityPolicy(url, csp); +} + } // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 8275928..d2e127a 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -41,6 +41,7 @@ class WebGraphicsContext3DProvider; class WebSecurityOrigin; enum class ProtocolHandlerSecurityLevel; +struct WebContentSecurityPolicyHeader; } // namespace blink namespace gpu { @@ -254,6 +255,9 @@ SkBitmap* GetSadPageBitmap() override; std::unique_ptr<blink::WebV8ValueConverter> CreateWebV8ValueConverter() override; + void AppendContentSecurityPolicy( + const blink::WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) override; // Tells this platform that the renderer is locked to a site (i.e., a scheme // plus eTLD+1, such as https://google.com), or to a more specific origin.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index f4dd1039..a1debdc 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1959,6 +1959,7 @@ "../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_service_impl_unittest.cc", "../browser/interest_group/interest_group_storage_unittest.cc", "../browser/loader/cors_origin_pattern_setter_unittest.cc", "../browser/loader/file_url_loader_factory_unittest.cc",
diff --git a/content/test/data/accessibility/event/same-page-link-navigation-expected-uia-win.txt b/content/test/data/accessibility/event/same-page-link-navigation-expected-uia-win.txt index 8a55ab0b..3347120 100644 --- a/content/test/data/accessibility/event/same-page-link-navigation-expected-uia-win.txt +++ b/content/test/data/accessibility/event/same-page-link-navigation-expected-uia-win.txt
@@ -1,6 +1,6 @@ -ActiveTextPositionChanged on role=link, name=Section 1 content +ActiveTextPositionChanged on role=document Invoke_Invoked on role=link, name=Section 1 ScrollVerticalScrollPercent changed on role=document === Start Continuation === -ActiveTextPositionChanged on role=link, name=Section 3 content -Invoke_Invoked on role=link, name=Section 3 +ActiveTextPositionChanged on role=document +Invoke_Invoked on role=link, name=Section 3 \ No newline at end of file
diff --git a/content/test/data/accessibility/event/same-page-link-navigation-expected-win.txt b/content/test/data/accessibility/event/same-page-link-navigation-expected-win.txt index 0567d76..b1f6014 100644 --- a/content/test/data/accessibility/event/same-page-link-navigation-expected-win.txt +++ b/content/test/data/accessibility/event/same-page-link-navigation-expected-win.txt
@@ -1,3 +1,3 @@ -EVENT_SYSTEM_SCROLLINGSTART on <a> role=ROLE_SYSTEM_LINK name="Section 1 content" +EVENT_SYSTEM_SCROLLINGSTART on <a> role=ROLE_SYSTEM_GROUPING === Start Continuation === -EVENT_SYSTEM_SCROLLINGSTART on <a> role=ROLE_SYSTEM_LINK name="Section 3 content" +EVENT_SYSTEM_SCROLLINGSTART on <a> role=ROLE_SYSTEM_GROUPING \ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-auralinux.txt b/content/test/data/accessibility/html/a-name-expected-auralinux.txt index 8194f69..709c1ca 100644 --- a/content/test/data/accessibility/html/a-name-expected-auralinux.txt +++ b/content/test/data/accessibility/html/a-name-expected-auralinux.txt
@@ -1,5 +1,5 @@ [document web] -++[link] name='named anchor' +++[section] ++++[static] name='named anchor' ++[link] name='both a named anchor and a link' -++++[static] name='both a named anchor and a link' +++++[static] name='both a named anchor and a link' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-blink.txt b/content/test/data/accessibility/html/a-name-expected-blink.txt index a1f23e9..3337a26 100644 --- a/content/test/data/accessibility/html/a-name-expected-blink.txt +++ b/content/test/data/accessibility/html/a-name-expected-blink.txt
@@ -1,9 +1,9 @@ rootWebArea ++genericContainer ignored ++++genericContainer ignored -++++++anchor name='named anchor' +++++++genericContainer ++++++++staticText name='named anchor' ++++++++++inlineTextBox name='named anchor' ++++++link name='both a named anchor and a link' ++++++++staticText name='both a named anchor and a link' -++++++++++inlineTextBox name='both a named anchor and a link' +++++++++++inlineTextBox name='both a named anchor and a link' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-mac.txt b/content/test/data/accessibility/html/a-name-expected-mac.txt index 0d05f4eb..f18b1bf 100644 --- a/content/test/data/accessibility/html/a-name-expected-mac.txt +++ b/content/test/data/accessibility/html/a-name-expected-mac.txt
@@ -1,5 +1,5 @@ AXWebArea -++AXGroup AXTitle='named anchor' +++AXGroup ++++AXStaticText AXValue='named anchor' ++AXLink AXDescription='both a named anchor and a link' -++++AXStaticText AXValue='both a named anchor and a link' +++++AXStaticText AXValue='both a named anchor and a link' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-uia-win.txt b/content/test/data/accessibility/html/a-name-expected-uia-win.txt index a0d54cc..1b9ef17 100644 --- a/content/test/data/accessibility/html/a-name-expected-uia-win.txt +++ b/content/test/data/accessibility/html/a-name-expected-uia-win.txt
@@ -1,5 +1,5 @@ Document -++Hyperlink Name='named anchor' +++Group IsControlElement=false ++++Text Name='named anchor' ++Hyperlink Name='both a named anchor and a link' -++++Text Name='both a named anchor and a link' IsControlElement=false +++++Text Name='both a named anchor and a link' IsControlElement=false \ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-win.txt b/content/test/data/accessibility/html/a-name-expected-win.txt index 28fef56..4c2453c 100644 --- a/content/test/data/accessibility/html/a-name-expected-win.txt +++ b/content/test/data/accessibility/html/a-name-expected-win.txt
@@ -1,5 +1,5 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_LINK name='named anchor' +++IA2_ROLE_SECTION ++++ROLE_SYSTEM_STATICTEXT name='named anchor' ++ROLE_SYSTEM_LINK name='both a named anchor and a link' FOCUSABLE LINKED -++++ROLE_SYSTEM_STATICTEXT name='both a named anchor and a link' LINKED +++++ROLE_SYSTEM_STATICTEXT name='both a named anchor and a link' LINKED \ No newline at end of file
diff --git a/content/test/data/accessibility/html/continuations-expected-auralinux.txt b/content/test/data/accessibility/html/continuations-expected-auralinux.txt index 73427c7..23dcfc44 100644 --- a/content/test/data/accessibility/html/continuations-expected-auralinux.txt +++ b/content/test/data/accessibility/html/continuations-expected-auralinux.txt
@@ -10,11 +10,11 @@ ++++[section] ++++++[static] name='After' ++[panel] name='Group 3' -++++[link] name='Before' +++++[section] ++++++[section] ++++++++[static] name='Before' ++++[section] -++++++[link] name='Ever ' +++++++[section] ++++++++[static] name='Ever ' ++++++[link] name='After' ++++++++[static] name='After' @@ -31,4 +31,4 @@ ++++[section] ++++++[static] name='Wow, another block!' ++++[static] name='More italic and bold text' -++++[static] name=' More italic text' +++++[static] name=' More italic text' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/continuations-expected-blink.txt b/content/test/data/accessibility/html/continuations-expected-blink.txt index e862d93..eed57a0 100644 --- a/content/test/data/accessibility/html/continuations-expected-blink.txt +++ b/content/test/data/accessibility/html/continuations-expected-blink.txt
@@ -17,12 +17,12 @@ ++++++++++staticText display='block' name='After' ++++++++++++inlineTextBox display='block' name='After' ++++++group display='block' name='Group 3' isLineBreakingObject=true -++++++++anchor display='inline' name='Before' +++++++++genericContainer display='inline' ++++++++++genericContainer display='block' isLineBreakingObject=true ++++++++++++staticText display='block' name='Before' ++++++++++++++inlineTextBox display='block' name='Before' ++++++++genericContainer display='block' isLineBreakingObject=true -++++++++++anchor display='inline' name='Ever ' +++++++++++genericContainer display='inline' ++++++++++++staticText display='inline' name='Ever ' ++++++++++++++inlineTextBox display='inline' name='Ever ' ++++++++++link display='inline' name='After'
diff --git a/content/test/data/accessibility/html/continuations-parser-splits-markup-expected-blink.txt b/content/test/data/accessibility/html/continuations-parser-splits-markup-expected-blink.txt new file mode 100644 index 0000000..6829cda --- /dev/null +++ b/content/test/data/accessibility/html/continuations-parser-splits-markup-expected-blink.txt
@@ -0,0 +1,15 @@ +rootWebArea isLineBreakingObject=true +++genericContainer ignored isLineBreakingObject=true +++++genericContainer ignored isLineBreakingObject=true +++++++genericContainer ignored isLineBreakingObject=true +++++++++genericContainer className='copied-element' display='inline' +++++++++++genericContainer className='before' display='block' isLineBreakingObject=true +++++++++++++staticText display='block' name='Before' +++++++++++++++inlineTextBox display='block' name='Before' +++++++++genericContainer className='ever' display='block' isLineBreakingObject=true +++++++++++genericContainer className='copied-element' display='inline' +++++++++++++staticText display='inline' name='Ever ' +++++++++++++++inlineTextBox display='inline' name='Ever ' +++++++++++link className='after' display='inline' name='After' +++++++++++++staticText display='inline' name='After' +++++++++++++++inlineTextBox display='inline' name='After'
diff --git a/content/test/data/accessibility/html/continuations-parser-splits-markup.html b/content/test/data/accessibility/html/continuations-parser-splits-markup.html new file mode 100644 index 0000000..b630ac7 --- /dev/null +++ b/content/test/data/accessibility/html/continuations-parser-splits-markup.html
@@ -0,0 +1,34 @@ +<!-- +@BLINK-ALLOW:display* +@BLINK-ALLOW:tag* +@BLINK-ALLOW:class* +@BLINK-ALLOW:isLineBreakingObject* +--> +<!-- The parser does not actually create the structure below, but rather + duplicates <a name="a">! both as a first child of the <span>, and a first + child of <div#ever>. The final DOM looks like: +<div> + <span> + <a name="a" class="copied-element"> + <div id="before" class="before">Before</div> + </a> + <div id="ever" class="ever"> + <a name="a" class="copied-element"> + Ever + </a> + <a href="#" class="after">After</a> + </div> + </span> +</div> +--> +<div> + <span> + <a name="a" class="copied-element"> + <div id="before" class="before">Before</div> + <div id="ever" class="ever"> + Ever + <a href="#" class="after">After</a> + </div> + </a> + </span> +</div>
diff --git a/content/test/data/accessibility/html/in-page-links-expected-auralinux.txt b/content/test/data/accessibility/html/in-page-links-expected-auralinux.txt index 03dc4387..943a572 100644 --- a/content/test/data/accessibility/html/in-page-links-expected-auralinux.txt +++ b/content/test/data/accessibility/html/in-page-links-expected-auralinux.txt
@@ -17,13 +17,13 @@ ++[link] name='Paragraph with content' ++++[static] name='Paragraph with content' ++[paragraph] -++++[link] +++++[section] ++++[static] name='After empty anchor' ++[paragraph] -++++[link] name='Anchor with content' +++++[section] ++++++[static] name='Anchor with content' ++[paragraph] -++++[link] name='Anchor with ID' +++++[section] ++++++[static] name='Anchor with ID' ++[paragraph] ++++[section] @@ -32,4 +32,4 @@ ++++[section] ++++++[static] name='Span with content' ++[paragraph] -++++[static] name='Paragraph with content' +++++[static] name='Paragraph with content' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/in-page-links-expected-blink.txt b/content/test/data/accessibility/html/in-page-links-expected-blink.txt index fd0f501d..b415386 100644 --- a/content/test/data/accessibility/html/in-page-links-expected-blink.txt +++ b/content/test/data/accessibility/html/in-page-links-expected-blink.txt
@@ -1,17 +1,17 @@ rootWebArea ++genericContainer ignored ++++genericContainer ignored -++++++link name='Empty anchor' defaultActionVerb=jump inPageLinkTargetId=anchor +++++++link name='Empty anchor' defaultActionVerb=jump inPageLinkTargetId=genericContainer ++++++++staticText name='Empty anchor' defaultActionVerb=clickAncestor ++++++++++inlineTextBox name='Empty anchor' ++++++staticText name=' ' ++++++++inlineTextBox name=' ' -++++++link name='Anchor with content' defaultActionVerb=jump inPageLinkTargetId=anchor +++++++link name='Anchor with content' defaultActionVerb=jump inPageLinkTargetId=genericContainer ++++++++staticText name='Anchor with content' defaultActionVerb=clickAncestor ++++++++++inlineTextBox name='Anchor with content' ++++++staticText name=' ' ++++++++inlineTextBox name=' ' -++++++link name='Anchor with ID' defaultActionVerb=jump inPageLinkTargetId=anchor +++++++link name='Anchor with ID' defaultActionVerb=jump inPageLinkTargetId=genericContainer ++++++++staticText name='Anchor with ID' defaultActionVerb=clickAncestor ++++++++++inlineTextBox name='Anchor with ID' ++++++staticText name=' ' @@ -30,15 +30,15 @@ ++++++++staticText name='Paragraph with content' defaultActionVerb=clickAncestor ++++++++++inlineTextBox name='Paragraph with content' ++++++paragraph -++++++++anchor +++++++++genericContainer ++++++++staticText name='After empty anchor' ++++++++++inlineTextBox name='After empty anchor' ++++++paragraph -++++++++anchor name='Anchor with content' +++++++++genericContainer ++++++++++staticText name='Anchor with content' ++++++++++++inlineTextBox name='Anchor with content' ++++++paragraph -++++++++anchor name='Anchor with ID' +++++++++genericContainer ++++++++++staticText name='Anchor with ID' ++++++++++++inlineTextBox name='Anchor with ID' ++++++paragraph @@ -51,4 +51,4 @@ ++++++++++++inlineTextBox name='Span with content' ++++++paragraph ++++++++staticText name='Paragraph with content' -++++++++++inlineTextBox name='Paragraph with content' +++++++++++inlineTextBox name='Paragraph with content' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/in-page-links-expected-mac.txt b/content/test/data/accessibility/html/in-page-links-expected-mac.txt index e93e6636..7a159d8 100644 --- a/content/test/data/accessibility/html/in-page-links-expected-mac.txt +++ b/content/test/data/accessibility/html/in-page-links-expected-mac.txt
@@ -20,10 +20,10 @@ ++++AXGroup ++++AXStaticText AXValue='After empty anchor' ++AXGroup -++++AXGroup AXTitle='Anchor with content' +++++AXGroup ++++++AXStaticText AXValue='Anchor with content' ++AXGroup -++++AXGroup AXTitle='Anchor with ID' +++++AXGroup ++++++AXStaticText AXValue='Anchor with ID' ++AXGroup ++++AXGroup @@ -32,4 +32,4 @@ ++++AXGroup ++++++AXStaticText AXValue='Span with content' ++AXGroup -++++AXStaticText AXValue='Paragraph with content' +++++AXStaticText AXValue='Paragraph with content' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/in-page-links-expected-uia-win.txt b/content/test/data/accessibility/html/in-page-links-expected-uia-win.txt index be7be40..2f6f3fc 100644 --- a/content/test/data/accessibility/html/in-page-links-expected-uia-win.txt +++ b/content/test/data/accessibility/html/in-page-links-expected-uia-win.txt
@@ -17,13 +17,13 @@ ++Hyperlink Name='Paragraph with content' ++++Text Name='Paragraph with content' IsControlElement=false ++Group IsControlElement=false -++++Hyperlink IsControlElement=false +++++Group IsControlElement=false ++++Text Name='After empty anchor' ++Group IsControlElement=false -++++Hyperlink Name='Anchor with content' +++++Group IsControlElement=false ++++++Text Name='Anchor with content' ++Group IsControlElement=false -++++Hyperlink Name='Anchor with ID' +++++Group IsControlElement=false ++++++Text Name='Anchor with ID' ++Group IsControlElement=false ++++Group IsControlElement=false
diff --git a/content/test/data/accessibility/html/in-page-links-expected-win.txt b/content/test/data/accessibility/html/in-page-links-expected-win.txt index e91e432..c49a99db 100644 --- a/content/test/data/accessibility/html/in-page-links-expected-win.txt +++ b/content/test/data/accessibility/html/in-page-links-expected-win.txt
@@ -17,13 +17,13 @@ ++ROLE_SYSTEM_LINK name='Paragraph with content' FOCUSABLE LINKED ++++ROLE_SYSTEM_STATICTEXT name='Paragraph with content' LINKED ++IA2_ROLE_PARAGRAPH -++++ROLE_SYSTEM_LINK +++++IA2_ROLE_SECTION ++++ROLE_SYSTEM_STATICTEXT name='After empty anchor' ++IA2_ROLE_PARAGRAPH -++++ROLE_SYSTEM_LINK name='Anchor with content' +++++IA2_ROLE_SECTION ++++++ROLE_SYSTEM_STATICTEXT name='Anchor with content' ++IA2_ROLE_PARAGRAPH -++++ROLE_SYSTEM_LINK name='Anchor with ID' +++++IA2_ROLE_SECTION ++++++ROLE_SYSTEM_STATICTEXT name='Anchor with ID' ++IA2_ROLE_PARAGRAPH ++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/html/svg-expected-blink.txt b/content/test/data/accessibility/html/svg-expected-blink.txt index efe48f9..1d54bcd 100644 --- a/content/test/data/accessibility/html/svg-expected-blink.txt +++ b/content/test/data/accessibility/html/svg-expected-blink.txt
@@ -1,7 +1,7 @@ rootWebArea ++genericContainer ignored ++++genericContainer -++++++svgRoot name='svg' +++++++svgRoot name='svg' tooltip='SVG Title Tag' ++++++++genericContainer ++++++++++staticText name='Test' ++++++++++++inlineTextBox name='Test'
diff --git a/content/test/data/accessibility/html/svg.html b/content/test/data/accessibility/html/svg.html index 9b5328d..0d069dc 100644 --- a/content/test/data/accessibility/html/svg.html +++ b/content/test/data/accessibility/html/svg.html
@@ -1,4 +1,5 @@ <!-- +@BLINK-ALLOW:tooltip* @UIA-WIN-ALLOW:HelpText* @MAC-ALLOW:AXDescription='svg' -->
diff --git a/content/test/data/conversions/databases/version_6.sql b/content/test/data/conversions/databases/version_6.sql index 190c2c0..6c9a6d2 100644 --- a/content/test/data/conversions/databases/version_6.sql +++ b/content/test/data/conversions/databases/version_6.sql
@@ -30,4 +30,32 @@ CREATE INDEX rate_limit_impression_id_idx ON rate_limits(impression_id); +INSERT INTO impressions +VALUES (1, + '9357e17751666f64', + 'https://a.impression.test', + 'https://conversion.test', + 'https://report.test', + 13245278349693988, + 13247870349693988, + 0, + 1, + 'https://conversion.test/', + 0, + 1, + 3), + (2, + '9357e17751666f64', + 'https://b.impression.test', + 'https://conversion.test', + 'https://report.test', + 13245278349693988, + 13247870349693988, + 0, + 1, + 'https://conversion.test/', + 0, + 1, + 4); + COMMIT;
diff --git a/content/test/data/conversions/databases/version_7.sql b/content/test/data/conversions/databases/version_7.sql new file mode 100644 index 0000000..a981811 --- /dev/null +++ b/content/test/data/conversions/databases/version_7.sql
@@ -0,0 +1,35 @@ +PRAGMA foreign_keys=OFF; + +BEGIN TRANSACTION; + +CREATE TABLE impressions(impression_id INTEGER PRIMARY KEY,impression_data TEXT NOT NULL,impression_origin TEXT NOT NULL,conversion_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,impression_time INTEGER NOT NULL,expiry_time INTEGER NOT NULL,num_conversions INTEGER DEFAULT 0,active INTEGER DEFAULT 1,conversion_destination TEXT NOT NULL,source_type INTEGER NOT NULL,attributed_truthfully INTEGER NOT NULL,priority INTEGER NOT NULL,impression_site TEXT NOT NULL); + +CREATE TABLE conversions (conversion_id INTEGER PRIMARY KEY, impression_id INTEGER, conversion_data TEXT NOT NULL, conversion_time INTEGER NOT NULL, report_time INTEGER NOT NULL); + +CREATE TABLE rate_limits(rate_limit_id INTEGER PRIMARY KEY,attribution_type INTEGER NOT NULL,impression_id INTEGER NOT NULL,impression_site TEXT NOT NULL,impression_origin TEXT NOT NULL,conversion_destination TEXT NOT NULL,conversion_origin TEXT NOT NULL,conversion_time INTEGER NOT NULL); + +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); + +INSERT INTO meta VALUES('mmap_status','-1'); +INSERT INTO meta VALUES('version','7'); +INSERT INTO meta VALUES('last_compatible_version','7'); + +CREATE INDEX conversion_destination_idx ON impressions(active, conversion_destination, reporting_origin); + +CREATE INDEX impression_expiry_idx ON impressions(expiry_time); + +CREATE INDEX impression_origin_idx ON impressions(impression_origin); + +CREATE INDEX impression_site_idx ON impressions(active, impression_site, source_type); + +CREATE INDEX conversion_report_idx ON conversions(report_time); + +CREATE INDEX conversion_impression_id_idx ON conversions(impression_id); + +CREATE INDEX rate_limit_impression_site_type_idx ON rate_limits(attribution_type, conversion_destination, impression_site, conversion_time); + +CREATE INDEX rate_limit_conversion_time_idx ON rate_limits(conversion_time); + +CREATE INDEX rate_limit_impression_id_idx ON rate_limits(impression_id); + +COMMIT;
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index f3b45557..625f03b 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -76,6 +76,9 @@ [ fuchsia ] GpuProcess_feature_status_under_swiftshader [ Skip ] [ fuchsia ] GpuProcess_swiftshader_for_webgl [ Skip ] +# Fuchsia flakes. +crbug.com/1207726 [ fuchsia ] GpuProcess_canvas2d [ RetryOnFailure ] + # SwiftShader GL does not work on CrOS, wait for it to be replaced by SwANGLE. crbug.com/1084794 [ chromeos ] GpuProcess_feature_status_under_swiftshader [ Skip ] crbug.com/1084794 [ chromeos ] GpuProcess_swiftshader_for_webgl [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 95f1cb3..fe15e2e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -355,6 +355,7 @@ crbug.com/1152619 [ win amd-0x7340 angle-d3d9 ] conformance/textures/misc/texture-npot-video.html [ Failure ] crbug.com/1152621 [ win amd-0x7340 angle-vulkan ] conformance/attribs/gl-vertexattribpointer-offsets.html [ Failure ] crbug.com/1152623 [ win amd-0x7340 angle-vulkan ] conformance/extensions/webgl-draw-buffers.html [ Failure ] +crbug.com/1215624 [ win amd-0x7340 angle-d3d11 ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ] # Win / D3D9 failures # Skipping these two tests because they're causing assertion failures.
diff --git a/content/test/web_contents_observer_consistency_checker.cc b/content/test/web_contents_observer_consistency_checker.cc index be23074..f5a030f 100644 --- a/content/test/web_contents_observer_consistency_checker.cc +++ b/content/test/web_contents_observer_consistency_checker.cc
@@ -16,9 +16,11 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_widget_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/test/test_utils.h" #include "net/base/net_errors.h" namespace content { @@ -83,6 +85,7 @@ << "not a current RenderFrameHost. Only the current frame should be " << "spawning children."; } + AddInputEventObserver(render_frame_host); } void WebContentsObserverConsistencyChecker::RenderFrameDeleted( @@ -116,6 +119,7 @@ // All players should have been paused by this point. for (const auto& id : active_media_players_) CHECK_NE(RenderFrameHost::FromID(id.frame_routing_id), render_frame_host); + RemoveInputEventObserver(render_frame_host); } void WebContentsObserverConsistencyChecker::RenderFrameHostChanged( @@ -457,4 +461,63 @@ return false; } +class WebContentsObserverConsistencyChecker::TestInputEventObserver + : public RenderWidgetHost::InputEventObserver { + public: + explicit TestInputEventObserver(RenderFrameHost& render_frame_host) + : render_frame_host_wrapper_(&render_frame_host), + render_widget_host_(static_cast<RenderWidgetHostImpl*>( + render_frame_host.GetRenderWidgetHost()) + ->GetWeakPtr()) { + render_widget_host_->AddInputEventObserver(this); + } + ~TestInputEventObserver() override { + if (render_widget_host_) + render_widget_host_->RemoveInputEventObserver(this); + } + + void OnInputEvent(const blink::WebInputEvent&) override { + EnsureRenderFrameHostNotPrerendered(); + } + void OnInputEventAck(blink::mojom::InputEventResultSource source, + blink::mojom::InputEventResultState state, + const blink::WebInputEvent&) override { + EnsureRenderFrameHostNotPrerendered(); + } + + private: + void EnsureRenderFrameHostNotPrerendered() { + if (render_frame_host_wrapper_.IsDestroyed()) + return; + + // TODO(crbug.com/1183639): Use RenderFrameHost::GetLifecycleState() if it + // is possible. + int frame_tree_node_id = + content::RenderFrameHost::GetFrameTreeNodeIdForRoutingId( + render_frame_host_wrapper_->GetProcess()->GetID(), + render_frame_host_wrapper_->GetRoutingID()); + CHECK(!FrameTreeNode::GloballyFindByID(frame_tree_node_id) + ->frame_tree() + ->is_prerendering()); + } + + RenderFrameHostWrapper render_frame_host_wrapper_; + base::WeakPtr<RenderWidgetHostImpl> render_widget_host_; +}; + +void WebContentsObserverConsistencyChecker::AddInputEventObserver( + RenderFrameHost* render_frame_host) { + auto result = input_observer_map_.insert(std::make_pair( + render_frame_host, + std::make_unique<TestInputEventObserver>(*render_frame_host))); + CHECK(result.second); +} + +void WebContentsObserverConsistencyChecker::RemoveInputEventObserver( + RenderFrameHost* render_frame_host) { + auto it = input_observer_map_.find(render_frame_host); + CHECK(it != input_observer_map_.end()); + input_observer_map_.erase(it); +} + } // namespace content
diff --git a/content/test/web_contents_observer_consistency_checker.h b/content/test/web_contents_observer_consistency_checker.h index 0e4ea66..6525173 100644 --- a/content/test/web_contents_observer_consistency_checker.h +++ b/content/test/web_contents_observer_consistency_checker.h
@@ -82,6 +82,8 @@ void DidStopLoading() override; private: + class TestInputEventObserver; + explicit WebContentsObserverConsistencyChecker(WebContents* web_contents); std::string Format(RenderFrameHost* render_frame_host); @@ -93,6 +95,9 @@ void EnsureStableParentValue(RenderFrameHost* render_frame_host); bool HasAnyChildren(RenderFrameHost* render_frame_host); + void AddInputEventObserver(RenderFrameHost* render_frame_host); + void RemoveInputEventObserver(RenderFrameHost* render_frame_host); + std::map<int64_t, RenderFrameHost*> ready_to_commit_hosts_; std::set<GlobalRoutingID> current_hosts_; std::set<GlobalRoutingID> live_routes_; @@ -101,6 +106,9 @@ std::set<NavigationHandle*> ongoing_navigations_; std::vector<MediaPlayerId> active_media_players_; + std::map<RenderFrameHost*, std::unique_ptr<TestInputEventObserver>> + input_observer_map_; + // Remembers parents to make sure RenderFrameHost::GetParent() never changes. std::map<GlobalRoutingID, GlobalRoutingID> parent_ids_;
diff --git a/crypto/ec_private_key.cc b/crypto/ec_private_key.cc index e4feb04b..2807804 100644 --- a/crypto/ec_private_key.cc +++ b/crypto/ec_private_key.cc
@@ -151,22 +151,16 @@ bool ECPrivateKey::ExportRawPublicKey(std::string* output) const { OpenSSLErrStackTracer err_tracer(FROM_HERE); - // Export the x and y field elements as 32-byte, big-endian numbers. (This is - // the same as X9.62 uncompressed form without the leading 0x04 byte.) + std::array<uint8_t, 65> buf; EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_.get()); - bssl::UniquePtr<BIGNUM> x(BN_new()); - bssl::UniquePtr<BIGNUM> y(BN_new()); - uint8_t buf[64]; - if (!x || !y || - !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), - EC_KEY_get0_public_key(ec_key), - x.get(), y.get(), nullptr) || - !BN_bn2bin_padded(buf, 32, x.get()) || - !BN_bn2bin_padded(buf + 32, 32, y.get())) { + if (!EC_POINT_point2oct(EC_KEY_get0_group(ec_key), + EC_KEY_get0_public_key(ec_key), + POINT_CONVERSION_UNCOMPRESSED, buf.data(), buf.size(), + /*ctx=*/nullptr)) { return false; } - output->assign(reinterpret_cast<const char*>(buf), sizeof(buf)); + output->assign(buf.begin(), buf.end()); return true; }
diff --git a/crypto/ec_private_key.h b/crypto/ec_private_key.h index 3e26599..50d9877f 100644 --- a/crypto/ec_private_key.h +++ b/crypto/ec_private_key.h
@@ -69,7 +69,8 @@ // Exports the public key to an X.509 SubjectPublicKeyInfo block. bool ExportPublicKey(std::vector<uint8_t>* output) const; - // Exports the public key as an EC point in the uncompressed point format. + // Exports the public key as an EC point in X9.62 uncompressed form. Note this + // includes the leading 0x04 byte. bool ExportRawPublicKey(std::string* output) const; private:
diff --git a/crypto/ec_private_key_unittest.cc b/crypto/ec_private_key_unittest.cc index cfec13c..c4662d09 100644 --- a/crypto/ec_private_key_unittest.cc +++ b/crypto/ec_private_key_unittest.cc
@@ -97,12 +97,12 @@ 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, }; static const uint8_t kRawPublicKey[] = { - 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, - 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, - 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, - 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, - 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, - 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, + 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, + 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, + 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, + 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, + 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, }; std::unique_ptr<crypto::ECPrivateKey> key = @@ -242,12 +242,12 @@ 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, }; static const uint8_t kOpenSSLRawPublicKey[] = { - 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67, 0xe7, - 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, 0xf6, - 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50, - 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb, - 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5, - 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, + 0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67, + 0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, + 0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, + 0x50, 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, + 0xfb, 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, + 0xc5, 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, }; std::unique_ptr<crypto::ECPrivateKey> keypair_openssl(
diff --git a/device/fido/cable/fido_ble_uuids.cc b/device/fido/cable/fido_ble_uuids.cc index f01930e..3dff9ed 100644 --- a/device/fido/cable/fido_ble_uuids.cc +++ b/device/fido/cable/fido_ble_uuids.cc
@@ -24,4 +24,10 @@ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, }; +const char kFIDOCableUUID128[] = "0000fff9-0000-1000-8000-00805f9b34fb"; +const uint8_t kFIDOCableUUID[16] = { + 0x00, 0x00, 0xff, 0xf9, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, +}; + } // namespace device
diff --git a/device/fido/cable/fido_ble_uuids.h b/device/fido/cable/fido_ble_uuids.h index 856ccff6..71d4d8c 100644 --- a/device/fido/cable/fido_ble_uuids.h +++ b/device/fido/cable/fido_ble_uuids.h
@@ -34,6 +34,11 @@ // |kGoogleCableUUID128|, the UUID allocated to Google for caBLE adverts. COMPONENT_EXPORT(DEVICE_FIDO) extern const uint8_t kGoogleCableUUID[16]; +// kFIDOCableUUID128 is a 16-bit UUID assigned to FIDO that is used for +// caBLEv2. (For now, caBLEv2 devices can also use |kGoogleCableUUID|.) +COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFIDOCableUUID128[]; +COMPONENT_EXPORT(DEVICE_FIDO) extern const uint8_t kFIDOCableUUID[16]; + } // namespace device #endif // DEVICE_FIDO_CABLE_FIDO_BLE_UUIDS_H_
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc index 7cb1290..81e55e5 100644 --- a/device/fido/cable/fido_cable_discovery.cc +++ b/device/fido/cable/fido_cable_discovery.cc
@@ -110,7 +110,11 @@ static bool IsCableUUID(const CableEidArray& eid) { static_assert(sizeof(kGoogleCableUUID) == EXTENT(eid), ""); - return memcmp(eid.data(), kGoogleCableUUID, sizeof(kGoogleCableUUID)) == 0; + static_assert(sizeof(kFIDOCableUUID) == EXTENT(eid), ""); + + return (memcmp(eid.data(), kGoogleCableUUID, sizeof(kGoogleCableUUID)) == + 0) || + (memcmp(eid.data(), kFIDOCableUUID, sizeof(kFIDOCableUUID)) == 0); } } // namespace @@ -217,16 +221,23 @@ // static const BluetoothUUID& FidoCableDiscovery::GoogleCableUUID() { - static const base::NoDestructor<BluetoothUUID> service_uuid( - kGoogleCableUUID128); - return *service_uuid; + static const base::NoDestructor<BluetoothUUID> kUUID(kGoogleCableUUID128); + return *kUUID; +} + +const BluetoothUUID& FidoCableDiscovery::FIDOCableUUID() { + static const base::NoDestructor<BluetoothUUID> kUUID(kFIDOCableUUID128); + return *kUUID; } // static bool FidoCableDiscovery::IsCableDevice(const BluetoothDevice* device) { - const auto& uuid = GoogleCableUUID(); - return base::Contains(device->GetServiceData(), uuid) || - base::Contains(device->GetUUIDs(), uuid); + const auto& uuid1 = GoogleCableUUID(); + const auto& uuid2 = FIDOCableUUID(); + return base::Contains(device->GetServiceData(), uuid1) || + base::Contains(device->GetUUIDs(), uuid1) || + base::Contains(device->GetServiceData(), uuid2) || + base::Contains(device->GetUUIDs(), uuid2); } void FidoCableDiscovery::OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter) { @@ -560,8 +571,11 @@ absl::optional<FidoCableDiscovery::V1DiscoveryDataAndEID> FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) { - const std::vector<uint8_t>* const service_data = + const std::vector<uint8_t>* service_data = device->GetServiceDataForUUID(GoogleCableUUID()); + if (!service_data) { + service_data = device->GetServiceDataForUUID(FIDOCableUUID()); + } absl::optional<CableEidArray> maybe_eid_from_service_data = MaybeGetEidFromServiceData(device); std::vector<CableEidArray> uuids = GetUUIDs(device);
diff --git a/device/fido/cable/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h index 43696722..a73b2c6 100644 --- a/device/fido/cable/fido_cable_discovery.h +++ b/device/fido/cable/fido_cable_discovery.h
@@ -78,6 +78,7 @@ }; static const BluetoothUUID& GoogleCableUUID(); + static const BluetoothUUID& FIDOCableUUID(); static bool IsCableDevice(const BluetoothDevice* device); // ResultDebugString returns a string containing a hex dump of |eid| and a
diff --git a/device/gamepad/raw_input_gamepad_device_win.cc b/device/gamepad/raw_input_gamepad_device_win.cc index 29a6812..2ca55e2 100644 --- a/device/gamepad/raw_input_gamepad_device_win.cc +++ b/device/gamepad/raw_input_gamepad_device_win.cc
@@ -26,29 +26,21 @@ namespace { -float NormalizeAxis(long value, long min, long max) { - return (2.f * (value - min) / static_cast<float>(max - min)) - 1.f; -} +constexpr uint32_t kGenericDesktopUsagePage = 0x01; +constexpr uint32_t kGameControlsUsagePage = 0x05; +constexpr uint32_t kButtonUsagePage = 0x09; +constexpr uint32_t kConsumerUsagePage = 0x0c; -unsigned long GetBitmask(unsigned short bits) { - return (1 << bits) - 1; -} - -const uint32_t kGenericDesktopUsagePage = 0x01; -const uint32_t kGameControlsUsagePage = 0x05; -const uint32_t kButtonUsagePage = 0x09; -const uint32_t kConsumerUsagePage = 0x0c; - -const uint32_t kAxisMinimumUsageNumber = 0x30; -const uint32_t kSystemMainMenuUsageNumber = 0x85; -const uint32_t kPowerUsageNumber = 0x30; -const uint32_t kSearchUsageNumber = 0x0221; -const uint32_t kHomeUsageNumber = 0x0223; -const uint32_t kBackUsageNumber = 0x0224; +constexpr uint32_t kAxisMinimumUsageNumber = 0x30; +constexpr uint32_t kSystemMainMenuUsageNumber = 0x85; +constexpr uint32_t kPowerUsageNumber = 0x30; +constexpr uint32_t kSearchUsageNumber = 0x0221; +constexpr uint32_t kHomeUsageNumber = 0x0223; +constexpr uint32_t kBackUsageNumber = 0x0224; // The fetcher will collect all HID usages from the Button usage page and any // additional usages listed below. -struct SpecialUsages { +constexpr struct SpecialUsages { const uint16_t usage_page; const uint16_t usage; } kSpecialUsages[] = { @@ -63,7 +55,19 @@ {kConsumerUsagePage, kHomeUsageNumber}, {kConsumerUsagePage, kBackUsageNumber}, }; -const size_t kSpecialUsagesLen = base::size(kSpecialUsages); +constexpr size_t kSpecialUsagesLen = base::size(kSpecialUsages); + +// Scales |value| from the range |min| <= x <= |max| to a Standard Gamepad axis +// value in the range -1.0 <= x <= 1.0. +template <class T> +float NormalizeAxis(T value, T min, T max) { + return (2.0f * (value - min) / static_cast<float>(max - min)) - 1.0f; +} + +// Returns a 32-bit mask with the lowest |bits| bits set. +unsigned long GetBitmask(unsigned short bits) { + return (1 << bits) - 1; +} } // namespace @@ -175,37 +179,9 @@ } } - // Query axis state. - ULONG axis_value = 0; - LONG scaled_axis_value = 0; - for (uint32_t i = 0; i < axes_length_; i++) { - RawGamepadAxis* axis = &axes_[i]; - - // If the min is < 0 we have to query the scaled value, otherwise we need - // the normal unscaled value. - if (axis->caps.LogicalMin < 0) { - status = HidP_GetScaledUsageValue( - HidP_Input, axis->caps.UsagePage, 0, axis->caps.Range.UsageMin, - &scaled_axis_value, preparsed_data_, - reinterpret_cast<PCHAR>(input->data.hid.bRawData), - input->data.hid.dwSizeHid); - if (status == HIDP_STATUS_SUCCESS) { - axis->value = NormalizeAxis(scaled_axis_value, axis->caps.PhysicalMin, - axis->caps.PhysicalMax); - } - } else { - status = HidP_GetUsageValue( - HidP_Input, axis->caps.UsagePage, 0, axis->caps.Range.UsageMin, - &axis_value, preparsed_data_, - reinterpret_cast<PCHAR>(input->data.hid.bRawData), - input->data.hid.dwSizeHid); - if (status == HIDP_STATUS_SUCCESS) { - axis->value = NormalizeAxis(axis_value & axis->bitmask, - axis->caps.LogicalMin & axis->bitmask, - axis->caps.LogicalMax & axis->bitmask); - } - } - } + // Update axis state. + for (uint32_t axis_index = 0; axis_index < axes_length_; ++axis_index) + UpdateAxisValue(axis_index, *input); last_update_timestamp_ = GamepadDataFetcher::CurrentTimeInMicroseconds(); } @@ -418,62 +394,55 @@ void RawInputGamepadDeviceWin::QueryButtonCapabilities(uint16_t button_count) { if (button_count > 0) { - std::unique_ptr<HIDP_BUTTON_CAPS[]> button_caps( - new HIDP_BUTTON_CAPS[button_count]); - NTSTATUS status = HidP_GetButtonCaps(HidP_Input, button_caps.get(), + std::vector<HIDP_BUTTON_CAPS> button_caps(button_count); + NTSTATUS status = HidP_GetButtonCaps(HidP_Input, button_caps.data(), &button_count, preparsed_data_); DCHECK_EQ(HIDP_STATUS_SUCCESS, status); // Collect all inputs from the Button usage page. - QueryNormalButtonCapabilities(button_caps.get(), button_count); + QueryNormalButtonCapabilities(button_caps); // Check for common gamepad buttons that are not on the Button usage page. - QuerySpecialButtonCapabilities(button_caps.get(), button_count); + QuerySpecialButtonCapabilities(button_caps); } } void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities( - HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count) { - DCHECK(button_caps); - + base::span<const HIDP_BUTTON_CAPS> button_caps) { // Collect all inputs from the Button usage page and assign button indices // based on the usage value. - for (size_t i = 0; i < button_count; ++i) { - uint16_t usage_page = button_caps[i].UsagePage; - uint16_t usage_min = button_caps[i].Range.UsageMin; - uint16_t usage_max = button_caps[i].Range.UsageMax; + for (const auto& item : button_caps) { + uint16_t usage_min = item.Range.UsageMin; + uint16_t usage_max = item.Range.UsageMax; if (usage_min == 0 || usage_max == 0) continue; size_t button_index_min = size_t{usage_min - 1}; size_t button_index_max = size_t{usage_max - 1}; - if (usage_page == kButtonUsagePage && + if (item.UsagePage == kButtonUsagePage && button_index_min < Gamepad::kButtonsLengthCap) { button_index_max = std::min(Gamepad::kButtonsLengthCap - 1, button_index_max); buttons_length_ = std::max(buttons_length_, button_index_max + 1); - for (size_t j = button_index_min; j <= button_index_max; ++j) - button_indices_used_[j] = true; + for (size_t button_index = button_index_min; + button_index <= button_index_max; ++button_index) { + button_indices_used_[button_index] = true; + } } } } void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities( - HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count) { - DCHECK(button_caps); - + base::span<const HIDP_BUTTON_CAPS> button_caps) { // Check for common gamepad buttons that are not on the Button usage page. std::vector<bool> has_special_usage(kSpecialUsagesLen, false); size_t unmapped_button_count = 0; - for (size_t i = 0; i < button_count; ++i) { - uint16_t usage_page = button_caps[i].UsagePage; - uint16_t usage_min = button_caps[i].Range.UsageMin; - uint16_t usage_max = button_caps[i].Range.UsageMax; + for (const auto& item : button_caps) { + uint16_t usage_min = item.Range.UsageMin; + uint16_t usage_max = item.Range.UsageMax; for (size_t special_index = 0; special_index < kSpecialUsagesLen; ++special_index) { const auto& special = kSpecialUsages[special_index]; - if (usage_page == special.usage_page && usage_min <= special.usage && + if (item.UsagePage == special.usage_page && usage_min <= special.usage && usage_max >= special.usage) { has_special_usage[special_index] = true; ++unmapped_button_count; @@ -557,6 +526,62 @@ } } +void RawInputGamepadDeviceWin::UpdateAxisValue(size_t axis_index, + RAWINPUT& input) { + DCHECK_LT(axis_index, Gamepad::kAxesLengthCap); + // RawInput gamepad axes are normalized according to the information provided + // in the HID report descriptor. Each HID report item must specify a Logical + // Minimum and Logical Maximum to define the domain of allowable values for + // the item. An item may optionally specify a Units definition to indicate + // that the item represents a real-world value measured in those units. Items + // with a Units definition should also specify Physical Minimum and Physical + // Maximum, which are the Logical bounds transformed into Physical units. + // + // For gamepads, it is common for joystick and trigger axis items to not + // specify Units. However, D-pad items typically do specify Units. An 8-way + // directional pad, when implemented as a Hat Switch axis, reports a logical + // value from 0 to 7 that corresponds to a physical value from 0 degrees (N) + // clockwise to 315 degrees (NW). + // + // When a Hat Switch is in its Null State (no interaction) it reports a value + // outside the Logical range, often 8. Normalizing the out-of-bounds Null + // State value yields an invalid axis value greater than +1.0. This invalid + // axis value must be preserved so that downstream consumers can detect when + // the Hat Switch is reporting a Null State value. + // + // When an item provides Physical bounds, prefer to use + // HidP_GetScaledUsageValue to retrieve the item's value in real-world units + // and normalize using the Physical bounds. If the Physical bounds are invalid + // or HidP_GetScaledUsageValue fails, use HidP_GetUsageValue to retrieve the + // logical value and normalize using the Logical bounds. + auto& axis = axes_[axis_index]; + if (axis.caps.PhysicalMin < axis.caps.PhysicalMax) { + LONG scaled_axis_value = 0; + if (HidP_GetScaledUsageValue( + HidP_Input, axis.caps.UsagePage, /*LinkCollection=*/0, + axis.caps.Range.UsageMin, &scaled_axis_value, preparsed_data_, + reinterpret_cast<PCHAR>(input.data.hid.bRawData), + input.data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS) { + axis.value = NormalizeAxis(scaled_axis_value, axis.caps.PhysicalMin, + axis.caps.PhysicalMax); + return; + } + } + + ULONG axis_value = 0; + if (HidP_GetUsageValue(HidP_Input, axis.caps.UsagePage, /*LinkCollection=*/0, + axis.caps.Range.UsageMin, &axis_value, preparsed_data_, + reinterpret_cast<PCHAR>(input.data.hid.bRawData), + input.data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS) { + axis.value = NormalizeAxis(axis_value & axis.bitmask, + axis.caps.LogicalMin & axis.bitmask, + axis.caps.LogicalMax & axis.bitmask); + return; + } + + axis.value = 0.0f; +} + base::WeakPtr<AbstractHapticGamepad> RawInputGamepadDeviceWin::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
diff --git a/device/gamepad/raw_input_gamepad_device_win.h b/device/gamepad/raw_input_gamepad_device_win.h index 25ea942b..aba234b89 100644 --- a/device/gamepad/raw_input_gamepad_device_win.h +++ b/device/gamepad/raw_input_gamepad_device_win.h
@@ -95,12 +95,16 @@ // on the device. bool QueryDeviceCapabilities(); void QueryButtonCapabilities(uint16_t button_count); - void QueryNormalButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count); - void QuerySpecialButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count); + void QueryNormalButtonCapabilities( + base::span<const HIDP_BUTTON_CAPS> button_caps); + void QuerySpecialButtonCapabilities( + base::span<const HIDP_BUTTON_CAPS> button_caps); void QueryAxisCapabilities(uint16_t axis_count); + // Reads the value of the axis at index |axis_index| from |input| and scales + // to the range [-1.0,+1.0]. + void UpdateAxisValue(size_t axis_index, RAWINPUT& input); + // True if the device described by this object is a valid RawInput gamepad. bool is_valid_ = false;
diff --git a/docs/accessibility/brltty.md b/docs/accessibility/brltty.md index e05f1d7..cd921d01 100644 --- a/docs/accessibility/brltty.md +++ b/docs/accessibility/brltty.md
@@ -169,6 +169,14 @@ matches the one in the new brltty. +#### ChromeVox +ChromeVox keeps a list of bluetooth braille display names +(search for bluetooth_display_manager.js). + +Within the brltty sources (as of 6.3), one can find all bluetooth display names +in: +brltty/Programs/bluetooth_names.c + ### Testing Firstly, try to test against brltty on linux. This involves building brltty at
diff --git a/docs/gpu/gpu_testing.md b/docs/gpu/gpu_testing.md index 67e4ce65f..8be60b7 100644 --- a/docs/gpu/gpu_testing.md +++ b/docs/gpu/gpu_testing.md
@@ -368,7 +368,7 @@ The easiest way to do this is to find the ID of the swarming task and use "swarming.py reproduce" to re-run it: -* `./src/tools/swarming_client/swarming.py reproduce -S https://chromium-swarm.appspot.com [task ID]` +* `./src/tools/luci-go/swarming reproduce -S https://chromium-swarm.appspot.com [task ID]` The task ID can be found in the stdio for the "trigger" step for the test. For example, look at a recent build from the [Mac Release (Intel)] bot, and @@ -405,8 +405,7 @@ to access the isolate server. Full instructions can be [found here][isolate-server-credentials]. For most cases, you can simply run: -* `./src/tools/swarming_client/auth.py login - --service=https://isolateserver.appspot.com` +* `./src/tools/luci-go/isolate login` The above link requires that you log in with your @google.com credentials. It's not known at the present time whether this works with @chromium.org accounts. @@ -420,7 +419,7 @@ Be sure to use the correct swarming dimensions for your desired GPU e.g. "1002:6613" instead of "AMD Radeon R7 240 (1002:6613)" which is how it appears on swarming task page. You can query bots in the chromium.tests.gpu pool to find the correct dimensions: -* `vpython tools\swarming_client\swarming.py bots -S chromium-swarm.appspot.com -d pool chromium.tests.gpu` +* `tools\luci-go\swarming bots -S chromium-swarm.appspot.com -d pool=chromium.tests.gpu` [Swarming documentation]: https://www.chromium.org/developers/testing/isolated-testing/for-swes#TOC-Run-a-test-built-locally-on-Swarming @@ -492,11 +491,7 @@ See the documentation from the GPU bot details on [adding new isolated tests][new-isolates] for the gn args and authentication needed to upload isolates to the isolate server. Most likely the new test will be Telemetry -based, and included in the `telemetry_gpu_test_run` isolate. You can then -invoke it via: - -* `./src/tools/swarming_client/run_isolated.py -s [HASH] - -I https://isolateserver.appspot.com -- [TEST_NAME] [TEST_ARGUMENTS]` +based, and included in the `telemetry_gpu_test_run` isolate. [new-isolates]: gpu_testing_bot_details.md#Adding-a-new-isolated-test-to-the-bots
diff --git a/docs/gpu/gpu_testing_bot_details.md b/docs/gpu/gpu_testing_bot_details.md index 850d860c..04186934 100644 --- a/docs/gpu/gpu_testing_bot_details.md +++ b/docs/gpu/gpu_testing_bot_details.md
@@ -46,7 +46,7 @@ 7-like NVIDIA bots in the pool, which necessitates the OS specifier.) Details about the bots can be found on [chromium-swarm.appspot.com] and by -using `src/tools/swarming_client/swarming.py`, for example `swarming.py bots`. +using `src/tools/luci-go/swarming`, for example `swarming bots`. If you are authenticated with @google.com credentials you will be able to make queries of the bots and see, for example, which GPUs are available. @@ -120,11 +120,8 @@ 1. `./tools/mb/mb.py isolate //out/Release [target name]` * For example: `./tools/mb/mb.py isolate //out/Release angle_end2end_tests` -1. `python tools/swarming_client/isolate.py batcharchive -I https://isolateserver.appspot.com out/Release/[target name].isolated.gen.json` - * For example: `python tools/swarming_client/isolate.py batcharchive -I https://isolateserver.appspot.com out/Release/angle_end2end_tests.isolated.gen.json` -1. This will write a hash to stdout. You can run it via: - `python tools/swarming_client/run_isolated.py -I https://isolateserver.appspot.com -s [HASH] -- [any additional args for the isolate]` - +1. `./tools/luci-go/isolate batcharchive -I https://isolateserver.appspot.com out/Release/[target name].isolated.gen.json` + * For example: `./tools/luci-go/isolate batcharchive -I https://isolateserver.appspot.com out/Release/angle_end2end_tests.isolated.gen.json` See the section below on [isolate server credentials](#Isolate-server-credentials). ### Adding your new isolate to the tests that are run on the bots @@ -212,7 +209,7 @@ * Definitions of how bots are organized on the waterfall, how builds are triggered, which VMs or machines are used for the builder itself, i.e. for compilation and scheduling swarmed tasks - on GPU hardware. See + on GPU hardware. See [README.md](https://chromium.googlesource.com/chromium/src/+/main/infra/config/README.md) in this directory for up to date information. @@ -331,7 +328,7 @@ GCEs from this small pool. 1. Run [`main.star`][main.star] to regenerate `configs/chromium-swarm/bots.cfg` and `configs/gce-provider/vms.cfg`. - Double-check your work there. + Double-check your work there. Note that previously [`vms.cfg`][vms.cfg] had to be edited manually. Part of the difficulty was in choosing a zone. This should soon no longer be necessary per [crbug.com/942301](http://crbug.com/942301), @@ -341,7 +338,7 @@ [dashboard](https://viceroy.corp.google.com/chrome_infra/Quota/chrome?duration=7d). 1. Get this reviewed and landed. This step associates the VM or pool of VMs with the bot's name on the waterfall for "builderful" bots or increases - swarmed pool capacity for "builderless" bots. + swarmed pool capacity for "builderless" bots. Note: CR+1 is not sticky in this repo, so you'll have to ping for re-review after every change, like rebase. @@ -369,7 +366,7 @@ 1. Work with the Chrome Infrastructure Labs team to get the (minimum 4) physical machines added to the Swarming pool. Use - [chromium-swarm.appspot.com] or `src/tools/swarming_client/swarming.py bots` + [chromium-swarm.appspot.com] or `src/tools/luci-go/swarming bots` to determine the PCI IDs of the GPUs in the bots. (These instructions will need to be updated for Android bots which don't have PCI buses.) @@ -732,8 +729,7 @@ To upload and download isolates you must first authenticate to the isolate server. From a Chromium checkout, run: -* `./src/tools/swarming_client/auth.py login - --service=https://isolateserver.appspot.com` +* `./src/tools/luci-go/isolate login` This will open a web browser to complete the authentication flow. A @google.com email address is required in order to properly authenticate. @@ -744,14 +740,6 @@ [Running Binaries from the Bots Locally]: https://www.chromium.org/developers/testing/gpu-testing#TOC-Running-Binaries-from-the-Bots-Locally -If authentication succeeded, this will silently download a file called -`delete_me` into the current working directory. If it failed, the script will -report multiple authentication errors. In this case, use the following command -to log out and then try again: - -* `./src/tools/swarming_client/auth.py logout - --service=https://isolateserver.appspot.com` - ### Swarming server credentials The swarming server uses the same `auth.py` script as the isolate server. You
diff --git a/docs/security/lookalikes/lookalike-domains.md b/docs/security/lookalikes/lookalike-domains.md index 6e1c28f..0415cce 100644 --- a/docs/security/lookalikes/lookalike-domains.md +++ b/docs/security/lookalikes/lookalike-domains.md
@@ -1,5 +1,9 @@ # "Lookalike" Warnings in Google Chrome +[TOC] + +## What are lookalike warnings? + "Lookalike" domains are domains that are crafted to impersonate the URLs of other sites in order to trick users into believing they're on a different site. These domains are used in social engineering attacks, from phishing to retail @@ -82,5 +86,4 @@ new sites in Chrome to ensure that their new domain does not trigger warnings. If you are a site operator and would like to request an appeal, please fill out -a -[request](https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals). +a [request](https://forms.gle/BxV3JGbCbRjucDxq6).
diff --git a/docs/testing/chromeos_debugging_tips.md b/docs/testing/chromeos_debugging_tips.md index 26f5927..aa0627a 100644 --- a/docs/testing/chromeos_debugging_tips.md +++ b/docs/testing/chromeos_debugging_tips.md
@@ -73,7 +73,7 @@ into a tmp directory and run: ``` $CHROME_DIR/tools/luci-go/isolated download -I https://chrome-isolated.appspot.com --namespace default-gzip -isolated 64919fee8b02d826df2401544a9dc0f7dfa2172d -output-dir input -python $CHROME_DIR/tools/swarming_client/swarming.py collect -S chrome-swarming.appspot.com 506a01dd12c8a610 --task-output-dir output +$CHROME_DIR/tools/luci-go/swarming collect -S chrome-swarming.appspot.com -output-dir output 506a01dd12c8a610 ``` Once both isolates have been fetched you must then generate the breakpad
diff --git a/docs/workflow/debugging-with-swarming.md b/docs/workflow/debugging-with-swarming.md index b0845a7..a656301 100644 --- a/docs/workflow/debugging-with-swarming.md +++ b/docs/workflow/debugging-with-swarming.md
@@ -153,14 +153,9 @@ ## Authenticating You may need to log in to `https://chromium-swarm.appspot.com` to do this -(for now you need to authenticate with python too, -TODO(https://crbug.com/984869): remove this): - ``` $ tools/luci-go/isolate login -$ python tools/swarming_client/auth.py login \ - --service=https://chromium-swarm.appspot.com ``` Use your google.com account for this.
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 4da01c1..b7d804c 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -816,6 +816,11 @@ return web_request_extension_count_ > 0; } +bool WebRequestAPI::HasExtraHeadersListenerForTesting() { + return ExtensionWebRequestEventRouter::GetInstance() + ->HasAnyExtraHeadersListener(browser_context_); +} + void WebRequestAPI::UpdateMayHaveProxies() { bool may_have_proxies = MayHaveProxies(); if (!may_have_proxies_ && may_have_proxies) {
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h index 5f04379..c68c1830 100644 --- a/extensions/browser/api/web_request/web_request_api.h +++ b/extensions/browser/api/web_request/web_request_api.h
@@ -233,6 +233,8 @@ // installed to support the API. bool MayHaveProxies() const; + bool HasExtraHeadersListenerForTesting(); + private: friend class BrowserContextKeyedAPIFactory<WebRequestAPI>;
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index 613c704..356de36 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -203,7 +203,15 @@ factory_->IsForServiceWorkerScript(), factory_->navigation_id_, ukm_source_id_)); + // The value of `has_any_extra_headers_listeners_` is constant for the + // lifetime of InProgressRequest and determines whether the request is made + // with the network::mojom::kURLLoadOptionUseHeaderClient option. To prevent + // the redirected request from getting into a state where + // `current_request_uses_header_client_` is true but the request is not made + // with the kURLLoadOptionUseHeaderClient option, also check + // `has_any_extra_headers_listeners_` here. See http://crbug.com/1074282. current_request_uses_header_client_ = + has_any_extra_headers_listeners_ && factory_->url_loader_header_client_receiver_.is_bound() && (request_.url.SchemeIsHTTPOrHTTPS() || request_.url.SchemeIs(url::kUrnScheme)) &&
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index e835898..15c56f1 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -218,7 +218,7 @@ // network::mojom::TrustedURLLoaderHeaderClient binding on the factory. This // is only set to true if there is a listener that needs to view or modify // headers set in the network process. - bool has_any_extra_headers_listeners_ = false; + const bool has_any_extra_headers_listeners_ = false; bool current_request_uses_header_client_ = false; OnBeforeSendHeadersCallback on_before_send_headers_callback_; OnHeadersReceivedCallback on_headers_received_callback_;
diff --git a/extensions/browser/extension_dialog_auto_confirm.cc b/extensions/browser/extension_dialog_auto_confirm.cc index e17fa6a..44daf5a 100644 --- a/extensions/browser/extension_dialog_auto_confirm.cc +++ b/extensions/browser/extension_dialog_auto_confirm.cc
@@ -2,28 +2,49 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + #include "extensions/browser/extension_dialog_auto_confirm.h" namespace extensions { namespace { -ScopedTestDialogAutoConfirm::AutoConfirm g_extension_dialog_auto_confirm = +ScopedTestDialogAutoConfirm::AutoConfirm g_extension_dialog_auto_confirm_value = ScopedTestDialogAutoConfirm::NONE; +int g_extension_dialog_option_to_select = 0; } ScopedTestDialogAutoConfirm::ScopedTestDialogAutoConfirm( - ScopedTestDialogAutoConfirm::AutoConfirm override_value) - : old_value_(g_extension_dialog_auto_confirm) { - g_extension_dialog_auto_confirm = override_value; -} + ScopedTestDialogAutoConfirm::AutoConfirm override_confirm_value) + : old_auto_confirm_value_( + std::exchange(g_extension_dialog_auto_confirm_value, + override_confirm_value)), + // Assign a default value if unspecified. + old_option_to_select_(0) {} + +ScopedTestDialogAutoConfirm::ScopedTestDialogAutoConfirm( + ScopedTestDialogAutoConfirm::AutoConfirm override_confirm_value, + int override_option_to_select) + : old_auto_confirm_value_( + std::exchange(g_extension_dialog_auto_confirm_value, + override_confirm_value)), + old_option_to_select_(std::exchange(g_extension_dialog_option_to_select, + override_option_to_select)) {} ScopedTestDialogAutoConfirm::~ScopedTestDialogAutoConfirm() { - g_extension_dialog_auto_confirm = old_value_; + g_extension_dialog_auto_confirm_value = old_auto_confirm_value_; + g_extension_dialog_option_to_select = old_option_to_select_; } +// static ScopedTestDialogAutoConfirm::AutoConfirm ScopedTestDialogAutoConfirm::GetAutoConfirmValue() { - return g_extension_dialog_auto_confirm; + return g_extension_dialog_auto_confirm_value; +} + +// static +int ScopedTestDialogAutoConfirm::GetOptionSelected() { + return g_extension_dialog_option_to_select; } } // namespace extensions
diff --git a/extensions/browser/extension_dialog_auto_confirm.h b/extensions/browser/extension_dialog_auto_confirm.h index 5d0c29e..693d635 100644 --- a/extensions/browser/extension_dialog_auto_confirm.h +++ b/extensions/browser/extension_dialog_auto_confirm.h
@@ -20,13 +20,32 @@ CANCEL, // The prompt will always cancel. }; - explicit ScopedTestDialogAutoConfirm(AutoConfirm override_value); + // Set up auto confirm value to |override_confirm_value| so the dialog is + // automatically shown, accepted, or cancelled. + explicit ScopedTestDialogAutoConfirm(AutoConfirm override_confirm_value); + + // Set up auto confirm value to |override_confirm_value| so the dialog is + // automatically shown, accepted, or cancelled. In addition, if a dialog is + // accepted and an option can be selected, accept the option specified by + // |override_option_to_select|. + ScopedTestDialogAutoConfirm(AutoConfirm override_confirm_value, + int override_option_to_select); ~ScopedTestDialogAutoConfirm(); + // Return whether the dialog should be showed, accepted, or cancelled. static AutoConfirm GetAutoConfirmValue(); + // Return which option is selected for the dialog. + static int GetOptionSelected(); + private: - AutoConfirm old_value_; + // Preserve the old auto confirm value so it can be reset when the dialog + // goes out of scope. + const AutoConfirm old_auto_confirm_value_; + + // Preserve the old option to select so it can be reset when the dialog goes + // out of scope. + const int old_option_to_select_; DISALLOW_COPY_AND_ASSIGN(ScopedTestDialogAutoConfirm); };
diff --git a/extensions/common/api/automation.idl b/extensions/common/api/automation.idl index 15f2411..e49ff6f5 100644 --- a/extensions/common/api/automation.idl +++ b/extensions/common/api/automation.idl
@@ -136,7 +136,6 @@ abbr, alert, alertDialog, - anchor, application, article, audio,
diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc index 209c373..a3844ae 100644 --- a/extensions/common/manifest_handlers/csp_info.cc +++ b/extensions/common/manifest_handlers/csp_info.cc
@@ -119,6 +119,12 @@ } // static +const std::string& CSPInfo::GetDefaultMV3ExtensionPagesCSP() { + static const base::NoDestructor<std::string> default_csp(kDefaultSecureCSP); + return *default_csp; +} + +// static const std::string* CSPInfo::GetIsolatedWorldCSP(const Extension& extension) { if (extension.manifest_version() >= 3) { // The isolated world will use its own CSP which blocks remotely hosted
diff --git a/extensions/common/manifest_handlers/csp_info.h b/extensions/common/manifest_handlers/csp_info.h index a2ba725..b22cf82 100644 --- a/extensions/common/manifest_handlers/csp_info.h +++ b/extensions/common/manifest_handlers/csp_info.h
@@ -37,6 +37,9 @@ // shouldn't be returned for those cases. static const std::string& GetExtensionPagesCSP(const Extension* extension); + // Returns the default extension pages CSP for Manifest V3 extensions. + static const std::string& GetDefaultMV3ExtensionPagesCSP(); + // Returns the Content Security Policy to be used for extension isolated // worlds or null if there is no defined CSP. static const std::string* GetIsolatedWorldCSP(const Extension& extension);
diff --git a/extensions/docs/security_faq.md b/extensions/docs/security_faq.md index 6662d4a0..4fa9ba9 100644 --- a/extensions/docs/security_faq.md +++ b/extensions/docs/security_faq.md
@@ -375,11 +375,15 @@ a bug in Chromium. However, they may be covered by the [Google Vulnerability Reward Program](https://www.google.com/about/appsecurity/reward-program/). -**Other Extensions:** A security bug in a third-party extension would not be -considered a security bug in Chromium. Some third-party extensions may have -their own vulnerability reward programs; please check with the extension -developer. It may also be eligible for a reward through the Developer Data -Protection Reward Program; visit +**Other Extensions:** A security bug in a third-party extension _would not_ be +considered a security bug in Chromium. This is true even if the extension has +sensitive and powerful permissions, which could leak user data or allow +cross-site scripting attacks +([example](https://bugs.chromium.org/p/chromium/issues/detail?id=1213523)). +Some third-party extensions may have their own vulnerability reward programs; +please check with the extension developer. It may also be eligible for a reward +through the Developer Data Protection Reward Program (though this typically +targets abuse, rather than vulnerabilities); visit [this site](https://www.google.com/about/appsecurity/ddprp/) for more information.
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc index 19f91ba..9a823a4 100644 --- a/extensions/renderer/native_extension_bindings_system.cc +++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -372,78 +372,6 @@ return false; } -// Logs the amount of time taken to update the bindings for a given context -// (i.e., UpdateBindingsForContext()). -void LogUpdateBindingsForContextTime(Feature::Context context_type, - bool is_for_service_worker, - base::TimeDelta elapsed) { - constexpr int kHistogramBucketCount = 50; - static const int kTenSecondsInMicroseconds = 10000000; - switch (context_type) { - case Feature::UNSPECIFIED_CONTEXT: - break; - case Feature::WEB_PAGE_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime.WebPageContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::BLESSED_WEB_PAGE_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "BlessedWebPageContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::BLESSED_EXTENSION_CONTEXT: - if (is_for_service_worker) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "ServiceWorkerContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - } else { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "BlessedExtensionContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - } - break; - case Feature::LOCK_SCREEN_EXTENSION_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "LockScreenExtensionContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::UNBLESSED_EXTENSION_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "UnblessedExtensionContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::CONTENT_SCRIPT_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime." - "ContentScriptContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::WEBUI_CONTEXT: - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Extensions.Bindings.UpdateBindingsForContextTime.WebUIContext", - elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds, - kHistogramBucketCount); - break; - case Feature::WEBUI_UNTRUSTED_CONTEXT: - // Extension APIs in untrusted WebUIs are temporary so don't bother - // recording metrics for them. - break; - } -} - // The APIs that could potentially be available to webpage-like contexts. // This is the list of possible features; most web pages will not have access // to these APIs. @@ -544,7 +472,6 @@ void NativeExtensionBindingsSystem::UpdateBindingsForContext( ScriptContext* context) { - base::ElapsedTimer timer; v8::Isolate* isolate = context->isolate(); v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> v8_context = context->v8_context(); @@ -599,9 +526,6 @@ if (IsRuntimeAvailableToContext(context) && !set_accessor("runtime")) LOG(ERROR) << "Failed to create API on Chrome object."; - LogUpdateBindingsForContextTime(context->context_type(), - context->IsForServiceWorker(), - timer.Elapsed()); UpdateContentCapabilities(context); return; } @@ -634,9 +558,6 @@ return; } } - - LogUpdateBindingsForContextTime( - context->context_type(), context->IsForServiceWorker(), timer.Elapsed()); } void NativeExtensionBindingsSystem::DispatchEventInContext(
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc index 5c5f882..b0ae16a 100644 --- a/fuchsia/engine/browser/frame_impl_browsertest.cc +++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -1328,6 +1328,8 @@ frame.ptr().get(), "window.devicePixelRatio"); ASSERT_TRUE(default_dpr); + EXPECT_EQ(default_dpr->GetDouble(), 1.0f); + // Update scale and verify that devicePixelRatio is updated accordingly. const float kZoomInScale = 1.5; frame->SetPageScale(kZoomInScale); @@ -1336,8 +1338,7 @@ frame.ptr().get(), "window.devicePixelRatio"); ASSERT_TRUE(scaled_dpr); - EXPECT_NEAR(scaled_dpr->GetDouble() / default_dpr->GetDouble(), kZoomInScale, - 1e-6); + EXPECT_EQ(scaled_dpr->GetDouble(), kZoomInScale); // Navigate to the same page on http://localhost. This is a different site, // so it will be loaded in a new renderer process. Page scale value should be @@ -1356,14 +1357,14 @@ EXPECT_EQ(dpr_after_navigation, scaled_dpr); - // Reset the scale to 1.0 (default) and verify that reported DPR is equal to - // the same as when the frame was created. + // Reset the scale to 1.0 (default) and verify that reported DPR is updated + // to 1.0. frame->SetPageScale(1.0); absl::optional<base::Value> dpr_after_reset = cr_fuchsia::ExecuteJavaScript( frame.ptr().get(), "window.devicePixelRatio"); ASSERT_TRUE(dpr_after_reset); - EXPECT_EQ(dpr_after_reset.value(), default_dpr.value()); + EXPECT_EQ(dpr_after_reset->GetDouble(), 1.0); // Zoom out by setting scale to 0.5. const float kZoomOutScale = 0.5; @@ -1373,8 +1374,7 @@ frame.ptr().get(), "window.devicePixelRatio"); ASSERT_TRUE(zoomed_out_dpr); - EXPECT_NEAR(zoomed_out_dpr->GetDouble() / default_dpr->GetDouble(), - kZoomOutScale, 1e-6); + EXPECT_EQ(zoomed_out_dpr->GetDouble(), kZoomOutScale); // Create another frame. Verify that the scale factor is not applied to the // new frame. @@ -1395,7 +1395,7 @@ frame2.ptr().get(), "window.devicePixelRatio"); ASSERT_TRUE(frame2_dpr); - EXPECT_EQ(frame2_dpr.value(), default_dpr.value()); + EXPECT_EQ(frame2_dpr->GetDouble(), 1.0); } // Send a MessagePort to the content, then perform bidirectional messaging
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index a3044fd3..ff13b21 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -26,8 +26,8 @@ #include "base/bits.h" #include "base/compiler_specific.h" #include "base/containers/span.h" +#include "base/cxx17_backports.h" #include "base/numerics/safe_math.h" -#include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/system/sys_info.h" #include "base/threading/thread_task_runner_handle.h"
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 1f4f495..71f83799 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -18,7 +18,7 @@ #include "base/bind.h" #include "base/compiler_specific.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/client/client_test_helper.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/mock_transfer_buffer.h"
diff --git a/gpu/command_buffer/client/program_info_manager_unittest.cc b/gpu/command_buffer/client/program_info_manager_unittest.cc index c9e652d..9ddaa9e4 100644 --- a/gpu/command_buffer/client/program_info_manager_unittest.cc +++ b/gpu/command_buffer/client/program_info_manager_unittest.cc
@@ -7,7 +7,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/client/program_info_manager.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/gpu/command_buffer/client/query_tracker_unittest.cc b/gpu/command_buffer/client/query_tracker_unittest.cc index 0b3982d..2015578 100644 --- a/gpu/command_buffer/client/query_tracker_unittest.cc +++ b/gpu/command_buffer/client/query_tracker_unittest.cc
@@ -13,7 +13,7 @@ #include <memory> #include <vector> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/client/client_test_helper.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/mapped_memory.h"
diff --git a/gpu/command_buffer/client/raster_implementation_unittest.cc b/gpu/command_buffer/client/raster_implementation_unittest.cc index 53af6b4a..629ad614 100644 --- a/gpu/command_buffer/client/raster_implementation_unittest.cc +++ b/gpu/command_buffer/client/raster_implementation_unittest.cc
@@ -16,8 +16,8 @@ #include "base/bind.h" #include "base/compiler_specific.h" +#include "base/cxx17_backports.h" #include "base/memory/ptr_util.h" -#include "base/stl_util.h" #include "cc/paint/raw_memory_transfer_cache_entry.h" #include "cc/paint/transfer_cache_serialize_helper.h" #include "gpu/command_buffer/client/client_test_helper.h"
diff --git a/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc b/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc index f11e84de..b536128 100644 --- a/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc +++ b/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc
@@ -12,7 +12,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu {
diff --git a/gpu/command_buffer/common/gles2_cmd_format.cc b/gpu/command_buffer/common/gles2_cmd_format.cc index 6371553..b66cf96 100644 --- a/gpu/command_buffer/common/gles2_cmd_format.cc +++ b/gpu/command_buffer/common/gles2_cmd_format.cc
@@ -12,7 +12,7 @@ #include <stddef.h> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" namespace gpu { namespace gles2 {
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 0b6e26a..0de243f 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -16,9 +16,9 @@ #include <sstream> #include "base/check_op.h" +#include "base/cxx17_backports.h" #include "base/notreached.h" #include "base/numerics/safe_math.h" -#include "base/stl_util.h" namespace gpu { namespace gles2 {
diff --git a/gpu/command_buffer/common/mailbox.cc b/gpu/command_buffer/common/mailbox.cc index f31a517..da8fda3 100644 --- a/gpu/command_buffer/common/mailbox.cc +++ b/gpu/command_buffer/common/mailbox.cc
@@ -9,8 +9,8 @@ #include <string.h> #include "base/check.h" +#include "base/cxx17_backports.h" #include "base/rand_util.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" namespace gpu {
diff --git a/gpu/command_buffer/common/raster_cmd_format.cc b/gpu/command_buffer/common/raster_cmd_format.cc index 6729d13c..dab0c9e 100644 --- a/gpu/command_buffer/common/raster_cmd_format.cc +++ b/gpu/command_buffer/common/raster_cmd_format.cc
@@ -11,7 +11,7 @@ #include <stddef.h> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" namespace gpu { namespace raster {
diff --git a/gpu/command_buffer/common/webgpu_cmd_format.cc b/gpu/command_buffer/common/webgpu_cmd_format.cc index 73e21dcf..468d828 100644 --- a/gpu/command_buffer/common/webgpu_cmd_format.cc +++ b/gpu/command_buffer/common/webgpu_cmd_format.cc
@@ -7,7 +7,7 @@ // We explicitly do NOT include webgpu_cmd_format.h here because client side // and service side have different requirements. -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" namespace gpu {
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc index 6968432..cffb866 100644 --- a/gpu/command_buffer/service/buffer_manager_unittest.cc +++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -7,7 +7,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/service/buffer_manager.h" #include "gpu/command_buffer/service/error_state_mock.h" #include "gpu/command_buffer/service/feature_info.h"
diff --git a/gpu/command_buffer/service/common_decoder.cc b/gpu/command_buffer/service/common_decoder.cc index e47dbf5..82dea1c 100644 --- a/gpu/command_buffer/service/common_decoder.cc +++ b/gpu/command_buffer/service/common_decoder.cc
@@ -9,8 +9,8 @@ #include <algorithm> +#include "base/cxx17_backports.h" #include "base/numerics/safe_math.h" -#include "base/stl_util.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/command_buffer/service/decoder_client.h" #include "ui/gfx/ipc/color/gfx_param_traits.h"
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc index ae998ca..18ca533 100644 --- a/gpu/command_buffer/service/external_vk_image_backing.cc +++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -7,7 +7,7 @@ #include <utility> #include <vector> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "build/build_config.h" #include "components/viz/common/resources/resource_sizes.h" #include "gpu/command_buffer/service/external_vk_image_gl_representation.h"
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index d8137c45..8ef9b9ee 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -12,9 +12,9 @@ #include "base/command_line.h" #include "base/containers/contains.h" +#include "base/cxx17_backports.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "build/build_config.h"
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index c783a2e..5dfcffb 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -7,7 +7,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/client/client_test_helper.h" #include "gpu/command_buffer/service/error_state_mock.h" #include "gpu/command_buffer/service/feature_info.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3612e8e..139d4ea 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -25,6 +25,7 @@ #include "base/containers/flat_set.h" #include "base/containers/queue.h" #include "base/containers/span.h" +#include "base/cxx17_backports.h" #include "base/debug/alias.h" #include "base/debug/dump_without_crashing.h" #include "base/hash/legacy_hash.h" @@ -32,7 +33,6 @@ #include "base/metrics/histogram_macros.h" #include "base/numerics/ranges.h" #include "base/numerics/safe_math.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index 8d6eb403..81d27a9 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -10,7 +10,7 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_split.h" #include "build/build_config.h" #include "gpu/command_buffer/service/command_buffer_service.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 4f8d623..baa0e9c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -9,7 +9,7 @@ #include "base/bind.h" #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc index de2a399..2c9b7702 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc
@@ -7,7 +7,7 @@ #include <stddef.h> #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 906f062..049becc 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -13,7 +13,7 @@ #include <vector> #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "gpu/command_buffer/common/gles2_cmd_format.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc index 04ecdd60..83082aa 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -11,8 +11,8 @@ #include <memory> #include "base/command_line.h" +#include "base/cxx17_backports.h" #include "base/numerics/ranges.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc index 6ec6b2fa..f0e6375 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
@@ -8,7 +8,7 @@ #include <stdint.h> #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc index 1e3c9b6..197ce21 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -8,7 +8,7 @@ #include <stdint.h> #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "components/viz/common/resources/resource_format_utils.h" #include "gpu/command_buffer/common/gles2_cmd_format.h"
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc index f6c29308..7ee9654 100644 --- a/gpu/command_buffer/service/gpu_tracer.cc +++ b/gpu/command_buffer/service/gpu_tracer.cc
@@ -8,9 +8,9 @@ #include <stdint.h> #include "base/bind.h" +#include "base/cxx17_backports.h" #include "base/location.h" #include "base/single_thread_task_runner.h" -#include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h"
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index e3985f92..ae6d27d5 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc
@@ -15,10 +15,10 @@ #include <vector> #include "base/command_line.h" +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_math.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/time/time.h"
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index f627ad8..696f66a 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -11,7 +11,7 @@ #include <memory> #include "base/command_line.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "gpu/command_buffer/common/gles2_cmd_format.h"
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index d258855..8433fbd 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -16,11 +16,11 @@ #include "base/bind.h" #include "base/bits.h" #include "base/containers/flat_map.h" +#include "base/cxx17_backports.h" #include "base/debug/crash_logging.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/stl_util.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "cc/paint/paint_cache.h"
diff --git a/gpu/command_buffer/service/scheduler.cc b/gpu/command_buffer/service/scheduler.cc index 60c27948..2fe4798 100644 --- a/gpu/command_buffer/service/scheduler.cc +++ b/gpu/command_buffer/service/scheduler.cc
@@ -95,14 +95,15 @@ Scheduler::PerThreadState& Scheduler::PerThreadState::operator=( PerThreadState&& other) = default; -Scheduler::Sequence::Sequence(Scheduler* scheduler, - SequenceId sequence_id, - base::PlatformThreadId thread_id, - SchedulingPriority priority, - scoped_refptr<SyncPointOrderData> order_data) +Scheduler::Sequence::Sequence( + Scheduler* scheduler, + SequenceId sequence_id, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + SchedulingPriority priority, + scoped_refptr<SyncPointOrderData> order_data) : scheduler_(scheduler), sequence_id_(sequence_id), - thread_id_(thread_id), + task_runner_(std::move(task_runner)), default_priority_(priority), current_priority_(priority), order_data_(std::move(order_data)) {} @@ -154,7 +155,7 @@ } bool Scheduler::Sequence::ShouldYieldTo(const Sequence* other) const { - if (thread_id() != other->thread_id()) + if (task_runner() != other->task_runner()) return false; if (!running() || !other->scheduled()) return false; @@ -393,20 +394,25 @@ DCHECK(!per_thread_state.second.running); } -SequenceId Scheduler::CreateSequence(SchedulingPriority priority) { +SequenceId Scheduler::CreateSequence( + SchedulingPriority priority, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { base::AutoLock auto_lock(lock_); scoped_refptr<SyncPointOrderData> order_data = sync_point_manager_->CreateSyncPointOrderData(); SequenceId sequence_id = order_data->sequence_id(); - auto task_runner = base::ThreadTaskRunnerHandle::Get(); - auto thread_id = base::PlatformThread::CurrentId(); - auto sequence = std::make_unique<Sequence>(this, sequence_id, thread_id, - priority, std::move(order_data)); + auto sequence = + std::make_unique<Sequence>(this, sequence_id, std::move(task_runner), + priority, std::move(order_data)); sequence_map_.emplace(sequence_id, std::move(sequence)); - per_thread_state_map_[thread_id].task_runner = task_runner; return sequence_id; } +SequenceId Scheduler::CreateSequenceForTesting(SchedulingPriority priority) { + // This will create the sequence on the thread on which this method is called. + return CreateSequence(priority, base::ThreadTaskRunnerHandle::Get()); +} + void Scheduler::DestroySequence(SequenceId sequence_id) { base::circular_deque<Sequence::Task> tasks_to_be_destroyed; { @@ -415,7 +421,7 @@ Sequence* sequence = GetSequence(sequence_id); DCHECK(sequence); if (sequence->scheduled()) { - per_thread_state_map_[sequence->thread_id()].rebuild_scheduling_queue = + per_thread_state_map_[sequence->task_runner()].rebuild_scheduling_queue = true; } @@ -479,7 +485,7 @@ Sequence* sequence = GetSequence(sequence_id); DCHECK(sequence); - auto task_runner = per_thread_state_map_[sequence->thread_id()].task_runner; + auto* task_runner = sequence->task_runner(); uint32_t order_num = sequence->ScheduleTask(std::move(task.closure), std::move(task.report_callback)); @@ -507,7 +513,7 @@ base::AutoLock auto_lock(lock_); Sequence* sequence = GetSequence(sequence_id); DCHECK(sequence); - DCHECK_EQ(base::PlatformThread::CurrentId(), sequence->thread_id()); + DCHECK(sequence->task_runner()->BelongsToCurrentThread()); sequence->ContinueTask(std::move(closure)); } @@ -517,10 +523,10 @@ Sequence* running_sequence = GetSequence(sequence_id); DCHECK(running_sequence); DCHECK(running_sequence->running()); - DCHECK_EQ(base::PlatformThread::CurrentId(), running_sequence->thread_id()); + DCHECK(running_sequence->task_runner()->BelongsToCurrentThread()); const auto& scheduling_queue = - RebuildSchedulingQueueIfNeeded(running_sequence->thread_id()); + RebuildSchedulingQueueIfNeeded(running_sequence->task_runner()); if (scheduling_queue.empty()) return false; @@ -546,8 +552,8 @@ void Scheduler::TryScheduleSequence(Sequence* sequence) { lock_.AssertAcquired(); - auto thread_id = sequence->thread_id(); - auto& thread_state = per_thread_state_map_[thread_id]; + auto* task_runner = sequence->task_runner(); + auto& thread_state = per_thread_state_map_[task_runner]; if (sequence->running()) { // Update priority of running sequence because of sync token releases. @@ -557,11 +563,12 @@ // Rebuild scheduling queue if priority changed for a scheduled sequence. DCHECK(thread_state.running); DCHECK(sequence->IsRunnable()); - per_thread_state_map_[thread_id].rebuild_scheduling_queue = true; + per_thread_state_map_[task_runner].rebuild_scheduling_queue = true; } else if (!sequence->scheduled() && sequence->IsRunnable()) { // Insert into scheduling queue if sequence isn't already scheduled. SchedulingState scheduling_state = sequence->SetScheduled(); - auto& scheduling_queue = per_thread_state_map_[thread_id].scheduling_queue; + auto& scheduling_queue = + per_thread_state_map_[task_runner].scheduling_queue; scheduling_queue.push_back(scheduling_state); std::push_heap(scheduling_queue.begin(), scheduling_queue.end(), &SchedulingState::Comparator); @@ -569,18 +576,18 @@ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("gpu", "Scheduler::Running", this); thread_state.running = true; run_next_task_scheduled_ = base::TimeTicks::Now(); - thread_state.task_runner->PostTask( - FROM_HERE, - base::BindOnce(&Scheduler::RunNextTask, base::Unretained(this))); + task_runner->PostTask(FROM_HERE, base::BindOnce(&Scheduler::RunNextTask, + base::Unretained(this))); } } } std::vector<Scheduler::SchedulingState>& -Scheduler::RebuildSchedulingQueueIfNeeded(base::PlatformThreadId thread_id) { +Scheduler::RebuildSchedulingQueueIfNeeded( + base::SingleThreadTaskRunner* task_runner) { lock_.AssertAcquired(); - auto& thread_state = per_thread_state_map_[thread_id]; + auto& thread_state = per_thread_state_map_[task_runner]; auto& scheduling_queue = thread_state.scheduling_queue; if (!thread_state.rebuild_scheduling_queue) @@ -591,7 +598,7 @@ for (const auto& kv : sequence_map_) { Sequence* sequence = kv.second.get(); if (!sequence->IsRunnable() || sequence->running() || - sequence->thread_id() != thread_id) { + sequence->task_runner() != task_runner) { continue; } SchedulingState scheduling_state = sequence->SetScheduled(); @@ -610,14 +617,14 @@ base::TimeTicks::Now() - run_next_task_scheduled_, base::TimeDelta::FromMicroseconds(10), base::TimeDelta::FromSeconds(30), 100); - auto thread_id = base::PlatformThread::CurrentId(); + auto* task_runner = base::ThreadTaskRunnerHandle::Get().get(); SchedulingState state; { - auto& scheduling_queue = RebuildSchedulingQueueIfNeeded(thread_id); + auto& scheduling_queue = RebuildSchedulingQueueIfNeeded(task_runner); if (scheduling_queue.empty()) { TRACE_EVENT_NESTABLE_ASYNC_END0("gpu", "Scheduler::Running", this); - per_thread_state_map_[thread_id].running = false; + per_thread_state_map_[task_runner].running = false; return; } @@ -631,7 +638,7 @@ Sequence* sequence = GetSequence(state.sequence_id); DCHECK(sequence); - DCHECK_EQ(sequence->thread_id(), thread_id); + DCHECK_EQ(sequence->task_runner(), task_runner); UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( "GPU.Scheduler.TaskDependencyTime", @@ -688,7 +695,7 @@ sequence->FinishTask(); if (sequence->IsRunnable()) { auto& scheduling_queue = - per_thread_state_map_[thread_id].scheduling_queue; + per_thread_state_map_[task_runner].scheduling_queue; SchedulingState scheduling_state = sequence->SetScheduled(); scheduling_queue.push_back(scheduling_state); @@ -703,17 +710,16 @@ 100); // Avoid scheduling another RunNextTask if we're done with all tasks. - auto& scheduling_queue = RebuildSchedulingQueueIfNeeded(thread_id); + auto& scheduling_queue = RebuildSchedulingQueueIfNeeded(task_runner); if (scheduling_queue.empty()) { TRACE_EVENT_NESTABLE_ASYNC_END0("gpu", "Scheduler::Running", this); - per_thread_state_map_[thread_id].running = false; + per_thread_state_map_[task_runner].running = false; return; } run_next_task_scheduled_ = base::TimeTicks::Now(); - per_thread_state_map_[thread_id].task_runner->PostTask( - FROM_HERE, - base::BindOnce(&Scheduler::RunNextTask, base::Unretained(this))); + task_runner->PostTask(FROM_HERE, base::BindOnce(&Scheduler::RunNextTask, + base::Unretained(this))); } base::TimeDelta Scheduler::TakeTotalBlockingTime() { @@ -727,9 +733,7 @@ base::SingleThreadTaskRunner* Scheduler::GetTaskRunnerForTesting( SequenceId sequence_id) { base::AutoLock auto_lock(lock_); - return (per_thread_state_map_[GetSequence(sequence_id)->thread_id()] - .task_runner) - .get(); + return GetSequence(sequence_id)->task_runner(); } } // namespace gpu
diff --git a/gpu/command_buffer/service/scheduler.h b/gpu/command_buffer/service/scheduler.h index 92cdcbb..de327231 100644 --- a/gpu/command_buffer/service/scheduler.h +++ b/gpu/command_buffer/service/scheduler.h
@@ -64,8 +64,13 @@ // Create a sequence with given priority. Returns an identifier for the // sequence that can be used with SyncPointManager for creating sync point // release clients. Sequences start off as enabled (see |EnableSequence|). - // Sequence could be created outside of GPU thread. - SequenceId CreateSequence(SchedulingPriority priority); + // Sequence is bound to the provided |task_runner|. + SequenceId CreateSequence( + SchedulingPriority priority, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + + // Should be only used for tests. + SequenceId CreateSequenceForTesting(SchedulingPriority priority); // Destroy the sequence and run any scheduled tasks immediately. Sequence // could be destroyed outside of GPU thread. @@ -135,7 +140,7 @@ public: Sequence(Scheduler* scheduler, SequenceId sequence_id, - base::PlatformThreadId thread_id, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, SchedulingPriority priority, scoped_refptr<SyncPointOrderData> order_data); @@ -147,7 +152,9 @@ return order_data_; } - base::PlatformThreadId thread_id() const { return thread_id_; } + base::SingleThreadTaskRunner* task_runner() const { + return task_runner_.get(); + } bool enabled() const { return enabled_; } @@ -312,7 +319,7 @@ Scheduler* const scheduler_; const SequenceId sequence_id_; - const base::PlatformThreadId thread_id_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; const SchedulingPriority default_priority_; SchedulingPriority current_priority_; @@ -351,7 +358,7 @@ // If the scheduling queue needs to be rebuild because a sequence changed // priority. std::vector<SchedulingState>& RebuildSchedulingQueueIfNeeded( - base::PlatformThreadId thread_id); + base::SingleThreadTaskRunner* task_runner); Sequence* GetSequence(SequenceId sequence_id); @@ -373,11 +380,10 @@ // SchedulingState with highest priority (lowest order) in front. std::vector<SchedulingState> scheduling_queue; bool rebuild_scheduling_queue = false; - - scoped_refptr<base::SingleThreadTaskRunner> task_runner; bool running = false; }; - base::flat_map<base::PlatformThreadId, PerThreadState> per_thread_state_map_; + base::flat_map<base::SingleThreadTaskRunner*, PerThreadState> + per_thread_state_map_; // Accumulated time the thread was blocked during running task base::TimeDelta total_blocked_time_;
diff --git a/gpu/command_buffer/service/scheduler_unittest.cc b/gpu/command_buffer/service/scheduler_unittest.cc index 3babe97..e921d556 100644 --- a/gpu/command_buffer/service/scheduler_unittest.cc +++ b/gpu/command_buffer/service/scheduler_unittest.cc
@@ -45,7 +45,7 @@ void RunAllPendingTasks() { SequenceId sequence_id = - scheduler()->CreateSequence(SchedulingPriority::kLow); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); scheduler()->ScheduleTask(Scheduler::Task( sequence_id, run_loop_.QuitClosure(), std::vector<SyncToken>())); run_loop_.Run(); @@ -62,7 +62,7 @@ TEST_F(SchedulerTest, ScheduledTasksRunInOrder) { SequenceId sequence_id = - scheduler()->CreateSequence(SchedulingPriority::kNormal); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); static int count = 0; int ran1 = 0; @@ -87,7 +87,7 @@ TEST_F(SchedulerTest, ScheduledTasksRunAfterReporting) { SequenceId sequence_id = - scheduler()->CreateSequence(SchedulingPriority::kNormal); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); bool ran = false; bool reported = false; @@ -113,7 +113,7 @@ TEST_F(SchedulerTest, ContinuedTasksRunFirst) { SequenceId sequence_id = - scheduler()->CreateSequence(SchedulingPriority::kNormal); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); static int count = 0; int ran1 = 0; @@ -153,7 +153,7 @@ protected: void CreateSequence(int sequence_key, SchedulingPriority priority) { - SequenceId sequence_id = scheduler()->CreateSequence(priority); + SequenceId sequence_id = scheduler()->CreateSequenceForTesting(priority); CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(sequence_key); scoped_refptr<SyncPointClientState> release_state = @@ -482,7 +482,7 @@ TEST_F(SchedulerTest, ReleaseSequenceShouldYield) { SequenceId sequence_id1 = - scheduler()->CreateSequence(SchedulingPriority::kLow); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); scoped_refptr<SyncPointClientState> release_state = @@ -504,7 +504,7 @@ int ran2 = 0; SyncToken sync_token(namespace_id, command_buffer_id, release); SequenceId sequence_id2 = - scheduler()->CreateSequence(SchedulingPriority::kHigh); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); scheduler()->ScheduleTask(Scheduler::Task( sequence_id2, GetClosure([&] { ran2 = ++count; }), {sync_token})); @@ -521,7 +521,7 @@ TEST_F(SchedulerTest, ReentrantEnableSequenceShouldNotDeadlock) { SequenceId sequence_id1 = - scheduler()->CreateSequence(SchedulingPriority::kHigh); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id1 = CommandBufferId::FromUnsafeValue(1); scoped_refptr<SyncPointClientState> release_state1 = @@ -529,7 +529,7 @@ namespace_id, command_buffer_id1, sequence_id1); SequenceId sequence_id2 = - scheduler()->CreateSequence(SchedulingPriority::kNormal); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); CommandBufferId command_buffer_id2 = CommandBufferId::FromUnsafeValue(2); scoped_refptr<SyncPointClientState> release_state2 = sync_point_manager()->CreateSyncPointClientState( @@ -576,11 +576,11 @@ TEST_F(SchedulerTest, ClientWaitIsPrioritized) { SequenceId sequence_id1 = - scheduler()->CreateSequence(SchedulingPriority::kNormal); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); SequenceId sequence_id2 = - scheduler()->CreateSequence(SchedulingPriority::kLow); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); SequenceId sequence_id3 = - scheduler()->CreateSequence(SchedulingPriority::kHigh); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); @@ -625,7 +625,7 @@ // schedule the task. base::RunLoop run_loop_temp; SequenceId sequence_id_run_loop = - scheduler()->CreateSequence(SchedulingPriority::kLow); + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); scheduler()->ScheduleTask(Scheduler::Task(sequence_id_run_loop, run_loop_temp.QuitClosure(), std::vector<SyncToken>())); @@ -642,9 +642,12 @@ } TEST_F(SchedulerTest, StreamPriorities) { - SequenceId seq_id1 = scheduler()->CreateSequence(SchedulingPriority::kLow); - SequenceId seq_id2 = scheduler()->CreateSequence(SchedulingPriority::kNormal); - SequenceId seq_id3 = scheduler()->CreateSequence(SchedulingPriority::kHigh); + SequenceId seq_id1 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); + SequenceId seq_id2 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); + SequenceId seq_id3 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id1 = CommandBufferId::FromUnsafeValue(1); @@ -705,9 +708,12 @@ } TEST_F(SchedulerTest, StreamDestroyRemovesPriorities) { - SequenceId seq_id1 = scheduler()->CreateSequence(SchedulingPriority::kLow); - SequenceId seq_id2 = scheduler()->CreateSequence(SchedulingPriority::kNormal); - SequenceId seq_id3 = scheduler()->CreateSequence(SchedulingPriority::kHigh); + SequenceId seq_id1 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); + SequenceId seq_id2 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); + SequenceId seq_id3 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id1 = CommandBufferId::FromUnsafeValue(1); @@ -755,9 +761,12 @@ // crbug.com/781585#5: Test RemoveWait/AddWait/RemoveWait sequence. TEST_F(SchedulerTest, StreamPriorityChangeWhileReleasing) { - SequenceId seq_id1 = scheduler()->CreateSequence(SchedulingPriority::kLow); - SequenceId seq_id2 = scheduler()->CreateSequence(SchedulingPriority::kNormal); - SequenceId seq_id3 = scheduler()->CreateSequence(SchedulingPriority::kHigh); + SequenceId seq_id1 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); + SequenceId seq_id2 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); + SequenceId seq_id3 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id1 = CommandBufferId::FromUnsafeValue(1); @@ -812,9 +821,12 @@ } TEST_F(SchedulerTest, CircularPriorities) { - SequenceId seq_id1 = scheduler()->CreateSequence(SchedulingPriority::kHigh); - SequenceId seq_id2 = scheduler()->CreateSequence(SchedulingPriority::kLow); - SequenceId seq_id3 = scheduler()->CreateSequence(SchedulingPriority::kNormal); + SequenceId seq_id1 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kHigh); + SequenceId seq_id2 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kLow); + SequenceId seq_id3 = + scheduler()->CreateSequenceForTesting(SchedulingPriority::kNormal); CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; CommandBufferId command_buffer_id2 = CommandBufferId::FromUnsafeValue(2);
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc index 209f0a40..5c9dddb 100644 --- a/gpu/command_buffer/service/service_utils.cc +++ b/gpu/command_buffer/service/service_utils.cc
@@ -160,6 +160,8 @@ gpu_preferences.enable_webgpu = command_line->HasSwitch(switches::kEnableUnsafeWebGPU) || command_line->HasSwitch(switches::kEnableUnsafeWebGPUService); + gpu_preferences.enable_webgpu_spirv = + command_line->HasSwitch(switches::kEnableUnsafeWebGPU); if (command_line->HasSwitch(switches::kEnableDawnBackendValidation)) { auto value = command_line->GetSwitchValueASCII( switches::kEnableDawnBackendValidation);
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc index cede4071..6ae530b 100644 --- a/gpu/command_buffer/service/sync_point_manager.cc +++ b/gpu/command_buffer/service/sync_point_manager.cc
@@ -9,11 +9,11 @@ #include <stdint.h> #include "base/bind.h" +#include "base/cxx17_backports.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" -#include "base/stl_util.h" namespace gpu {
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index da9d7c4c..316a094 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -10,7 +10,7 @@ #include <algorithm> #include <string> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "gpu/command_buffer/service/buffer_manager.h" #include "gpu/command_buffer/service/error_state_mock.h"
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 528a13b..3e0b11b4 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -13,9 +13,9 @@ #include <utility> #include "base/bits.h" +#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/lazy_instance.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h"
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index 63b4e115..fdf6ad6 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -418,6 +418,7 @@ std::unique_ptr<dawn_native::Instance> dawn_instance_; std::vector<dawn_native::Adapter> dawn_adapters_; + bool allow_spirv_ = false; std::vector<std::string> force_enabled_toggles_; std::vector<std::string> force_disabled_toggles_; @@ -503,6 +504,7 @@ break; } + allow_spirv_ = gpu_preferences.enable_webgpu_spirv; force_enabled_toggles_ = gpu_preferences.enabled_dawn_features_list; force_disabled_toggles_ = gpu_preferences.disabled_dawn_features_list; @@ -564,6 +566,12 @@ "not_supported_extension_for_test"); } + // Disallows usage of SPIR-V by default for security (we only ensure that WGSL + // is secure), unless --enable-unsafe-webgpu is used. + if (!allow_spirv_) { + device_descriptor.forceEnabledToggles.push_back("disallow_spirv"); + } + for (const std::string& toggles : force_enabled_toggles_) { device_descriptor.forceEnabledToggles.push_back(toggles.c_str()); }
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc index d8fb127..c3546d1 100644 --- a/gpu/command_buffer/tests/fuzzer_main.cc +++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -12,10 +12,10 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/cxx17_backports.h" #include "base/i18n/icu_util.h" #include "base/logging.h" #include "base/memory/ref_counted.h" -#include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "build/build_config.h"
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index 5b7a3855..5fbf4e2 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -13,8 +13,8 @@ #include <stddef.h> #include <stdint.h> +#include "base/cxx17_backports.h" #include "base/logging.h" -#include "base/stl_util.h" #include "build/build_config.h" #include "gpu/command_buffer/tests/gl_manager.h" #include "gpu/command_buffer/tests/gl_test_utils.h"
diff --git a/gpu/command_buffer/tests/gl_cube_map_texture_unittest.cc b/gpu/command_buffer/tests/gl_cube_map_texture_unittest.cc index 2fde0c5c..4c092dc 100644 --- a/gpu/command_buffer/tests/gl_cube_map_texture_unittest.cc +++ b/gpu/command_buffer/tests/gl_cube_map_texture_unittest.cc
@@ -7,7 +7,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/tests/gl_manager.h" #include "gpu/command_buffer/tests/gl_test_utils.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/gpu/command_buffer/tests/gl_depth_texture_unittest.cc b/gpu/command_buffer/tests/gl_depth_texture_unittest.cc index d720005..df76a54 100644 --- a/gpu/command_buffer/tests/gl_depth_texture_unittest.cc +++ b/gpu/command_buffer/tests/gl_depth_texture_unittest.cc
@@ -7,7 +7,7 @@ #include <stddef.h> #include <stdint.h> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/command_buffer/tests/gl_manager.h" #include "gpu/command_buffer/tests/gl_test_utils.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/gpu/command_buffer/tests/gl_helper_benchmark.cc b/gpu/command_buffer/tests/gl_helper_benchmark.cc index 85b7d0b9..86325de 100644 --- a/gpu/command_buffer/tests/gl_helper_benchmark.cc +++ b/gpu/command_buffer/tests/gl_helper_benchmark.cc
@@ -21,9 +21,9 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/cxx17_backports.h" #include "base/files/file_util.h" #include "base/run_loop.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h"
diff --git a/gpu/command_buffer/tests/gl_helper_unittest.cc b/gpu/command_buffer/tests/gl_helper_unittest.cc index d0fb916..5c40d81 100644 --- a/gpu/command_buffer/tests/gl_helper_unittest.cc +++ b/gpu/command_buffer/tests/gl_helper_unittest.cc
@@ -17,10 +17,10 @@ #include <vector> #include "base/bind.h" +#include "base/cxx17_backports.h" #include "base/memory/ref_counted_memory.h" #include "base/numerics/ranges.h" #include "base/run_loop.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread_task_runner_handle.h"
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc index cab561f..999708b 100644 --- a/gpu/command_buffer/tests/webgpu_test.cc +++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -329,4 +329,38 @@ GetNewDevice(); } +TEST_F(WebGPUTest, SPIRVIsDisallowed) { + auto ExpectSPIRVDisallowedError = [](WGPUErrorType type, const char* message, + void* userdata) { + // We match on this string to make sure the shader module creation fails + // because SPIR-V is disallowed and not because codeSize=0. + EXPECT_NE(std::string(message).find("SPIR-V is disallowed"), + std::string::npos); + EXPECT_EQ(type, WGPUErrorType_Validation); + *static_cast<bool*>(userdata) = true; + }; + + // The initialization code doesn't set GpuPreferences::enable_webgpu_spirv so + // it stays at the default value of "false". + Initialize(WebGPUTest::Options()); + wgpu::Device device = GetNewDevice(); + + // Make a invalid ShaderModuleDescriptor because it contains SPIR-V. + wgpu::ShaderModuleSPIRVDescriptor spirvDesc; + spirvDesc.codeSize = 0; + spirvDesc.code = nullptr; + + wgpu::ShaderModuleDescriptor desc; + desc.nextInChain = &spirvDesc; + + // Make sure creation fails, and for the correct reason. + device.PushErrorScope(wgpu::ErrorFilter::Validation); + device.CreateShaderModule(&desc); + bool got_error = false; + device.PopErrorScope(ExpectSPIRVDisallowedError, &got_error); + + WaitForCompletion(device); + EXPECT_TRUE(got_error); +} + } // namespace gpu
diff --git a/gpu/config/gpu_control_list_entry_unittest.cc b/gpu/config/gpu_control_list_entry_unittest.cc index 4ff3570..931b991e 100644 --- a/gpu/config/gpu_control_list_entry_unittest.cc +++ b/gpu/config/gpu_control_list_entry_unittest.cc
@@ -4,7 +4,7 @@ #include <stddef.h> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "build/build_config.h" #include "gpu/config/gpu_control_list.h" #include "gpu/config/gpu_control_list_testing_data.h"
diff --git a/gpu/config/gpu_driver_bug_list.cc b/gpu/config/gpu_driver_bug_list.cc index ebf579a..f2c2333 100644 --- a/gpu/config/gpu_driver_bug_list.cc +++ b/gpu/config/gpu_driver_bug_list.cc
@@ -5,7 +5,7 @@ #include "gpu/config/gpu_driver_bug_list.h" #include "base/check_op.h" -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "gpu/config/gpu_driver_bug_list_autogen.h" #include "gpu/config/gpu_driver_bug_workaround_type.h" #include "gpu/config/gpu_switches.h"
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index 84f8ed45d..09dfc6e 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -3693,6 +3693,21 @@ "features": [ "disallow_vp9_resilient_dxva_decoding" ] + }, + { + "id": 375, + "cr_bugs": [1212825], + "description": "Always force direct composition full damage on older Windows 10 releases", + "os": { + "type": "win", + "version": { + "op": "<", + "value": "10.0.19041.508" + } + }, + "features": [ + "force_direct_composition_full_damage_always" + ] } ] }
diff --git a/gpu/config/gpu_dx_diagnostics_win.cc b/gpu/config/gpu_dx_diagnostics_win.cc index 43562b0..becf06e7 100644 --- a/gpu/config/gpu_dx_diagnostics_win.cc +++ b/gpu/config/gpu_dx_diagnostics_win.cc
@@ -9,7 +9,7 @@ #include <dxdiag.h> #include <windows.h> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/win/com_init_util.h"
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc index 15af5dff..878c8da 100644 --- a/gpu/config/gpu_info_collector.cc +++ b/gpu/config/gpu_info_collector.cc
@@ -12,9 +12,9 @@ #include <vector> #include "base/command_line.h" +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h"
diff --git a/gpu/config/gpu_preferences.h b/gpu/config/gpu_preferences.h index a5fa582..c5733e52 100644 --- a/gpu/config/gpu_preferences.h +++ b/gpu/config/gpu_preferences.h
@@ -252,6 +252,10 @@ // Enable the WebGPU command buffer. bool enable_webgpu = false; + // Enable usage of SPIR-V with WebGPU. This is unsafe since SPIR-V from the + // renderer process isn't fully validated. + bool enable_webgpu_spirv = false; + // Enable validation layers in Dawn backends. DawnBackendValidationLevel enable_dawn_backend_validation = DawnBackendValidationLevel::kDisabled;
diff --git a/gpu/config/gpu_workaround_list.txt b/gpu/config/gpu_workaround_list.txt index 74efadc1..c9103bc 100644 --- a/gpu/config/gpu_workaround_list.txt +++ b/gpu/config/gpu_workaround_list.txt
@@ -69,6 +69,7 @@ flush_on_framebuffer_change force_cube_complete force_cube_map_positive_x_allocation +force_direct_composition_full_damage_always force_enable_color_buffer_float force_enable_color_buffer_float_except_rgb32f force_gl_flush_on_swap_buffers
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc index 62ab1be..d7752a2 100644 --- a/gpu/gles2_conform_support/egl/display.cc +++ b/gpu/gles2_conform_support/egl/display.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "build/build_config.h" #include "gpu/gles2_conform_support/egl/config.h" #include "gpu/gles2_conform_support/egl/context.h"
diff --git a/gpu/ipc/client/gpu_channel_host.cc b/gpu/ipc/client/gpu_channel_host.cc index 105c328..a1e981a 100644 --- a/gpu/ipc/client/gpu_channel_host.cc +++ b/gpu/ipc/client/gpu_channel_host.cc
@@ -52,16 +52,9 @@ static_cast<int32_t>( GpuChannelReservedRoutes::kImageDecodeAccelerator)) { mojo::PendingAssociatedRemote<mojom::GpuChannel> channel; - auto receiver = channel.InitWithNewEndpointAndPassReceiver(); - if (io_thread_->BelongsToCurrentThread()) { - listener_->Initialize(std::move(handle), std::move(receiver), io_thread_); - } else { - io_thread_->PostTask( - FROM_HERE, - base::BindOnce(&Listener::Initialize, base::Unretained(listener_.get()), - std::move(handle), std::move(receiver), io_thread_)); - } - + listener_->Initialize(std::move(handle), + channel.InitWithNewEndpointAndPassReceiver(), + io_thread_); gpu_channel_ = mojo::SharedAssociatedRemote<mojom::GpuChannel>( std::move(channel), io_thread_); @@ -297,8 +290,7 @@ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { channel_ = IPC::ChannelMojo::Create( std::move(handle), IPC::Channel::MODE_CLIENT, this, io_task_runner, - base::ThreadTaskRunnerHandle::Get(), - mojo::internal::MessageQuotaChecker::MaybeCreate()); + io_task_runner, mojo::internal::MessageQuotaChecker::MaybeCreate()); DCHECK(channel_); bool result = channel_->Connect(); DCHECK(result);
diff --git a/gpu/ipc/client/gpu_channel_host.h b/gpu/ipc/client/gpu_channel_host.h index d42478d3..89b3b5a 100644 --- a/gpu/ipc/client/gpu_channel_host.h +++ b/gpu/ipc/client/gpu_channel_host.h
@@ -166,7 +166,7 @@ Listener(); ~Listener() override; - // Called on the IO thread. + // Called on the GpuChannelHost's thread. void Initialize(mojo::ScopedMessagePipeHandle handle, mojo::PendingAssociatedReceiver<mojom::GpuChannel> receiver, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy_unittest.cc b/gpu/ipc/client/image_decode_accelerator_proxy_unittest.cc index 2a90e2f..75139ae9 100644 --- a/gpu/ipc/client/image_decode_accelerator_proxy_unittest.cc +++ b/gpu/ipc/client/image_decode_accelerator_proxy_unittest.cc
@@ -6,7 +6,7 @@ #include <utility> #include <vector> -#include "base/stl_util.h" +#include "base/cxx17_backports.h" #include "base/test/task_environment.h" #include "cc/paint/paint_image.h" #include "gpu/ipc/client/gpu_channel_host.h"
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom index b24af43..d0871c7 100644 --- a/gpu/ipc/common/gpu_preferences.mojom +++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -92,6 +92,7 @@ bool enable_metal; bool enable_gpu_benchmarking_extension; bool enable_webgpu; + bool enable_webgpu_spirv; DawnBackendValidationLevel enable_dawn_backend_validation; array<string> enabled_dawn_features_list; array<string> disabled_dawn_features_list;
diff --git a/gpu/ipc/common/gpu_preferences_mojom_traits.h b/gpu/ipc/common/gpu_preferences_mojom_traits.h index e7b79cf..69d8209 100644 --- a/gpu/ipc/common/gpu_preferences_mojom_traits.h +++ b/gpu/ipc/common/gpu_preferences_mojom_traits.h
@@ -209,6 +209,7 @@ out->enable_gpu_benchmarking_extension = prefs.enable_gpu_benchmarking_extension(); out->enable_webgpu = prefs.enable_webgpu(); + out->enable_webgpu_spirv = prefs.enable_webgpu_spirv(); if (!prefs.ReadEnableDawnBackendValidation( &out->enable_dawn_backend_validation)) return false; @@ -400,6 +401,9 @@ static bool enable_webgpu(const gpu::GpuPreferences& prefs) { return prefs.enable_webgpu; } + static bool enable_webgpu_spirv(const gpu::GpuPreferences& prefs) { + return prefs.enable_webgpu_spirv; + } static gpu::DawnBackendValidationLevel enable_dawn_backend_validation( const gpu::GpuPreferences& prefs) { return prefs.enable_dawn_backend_validation;
diff --git a/gpu/ipc/gpu_in_process_thread_service.cc b/gpu/ipc/gpu_in_process_thread_service.cc index 24cf2d3b..2d71838 100644 --- a/gpu/ipc/gpu_in_process_thread_service.cc +++ b/gpu/ipc/gpu_in_process_thread_service.cc
@@ -53,28 +53,7 @@ std::unique_ptr<SingleTaskSequence> GpuInProcessThreadService::CreateSequence() { - // Create the SingleTaskSequence on the gpu thread. This is important since - // the sequences are now run on the thread it was created on. - std::unique_ptr<SingleTaskSequence> sequence; - if (task_runner_->BelongsToCurrentThread()) { - sequence = std::make_unique<SchedulerSequence>(scheduler_); - } else { - base::WaitableEvent completion; - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GpuInProcessThreadService::CreateSequenceOnThread, - base::Unretained(this), &sequence, &completion)); - completion.Wait(); - } - return sequence; -} - -void GpuInProcessThreadService::CreateSequenceOnThread( - std::unique_ptr<SingleTaskSequence>* sequence, - base::WaitableEvent* completion) { - DCHECK(task_runner_->BelongsToCurrentThread()); - *sequence = std::make_unique<SchedulerSequence>(scheduler_); - completion->Signal(); + return std::make_unique<SchedulerSequence>(scheduler_, task_runner_); } void GpuInProcessThreadService::ScheduleOutOfOrderTask(base::OnceClosure task) {
diff --git a/gpu/ipc/gpu_in_process_thread_service.h b/gpu/ipc/gpu_in_process_thread_service.h index 45ea2ca1..442861a 100644 --- a/gpu/ipc/gpu_in_process_thread_service.h +++ b/gpu/ipc/gpu_in_process_thread_service.h
@@ -69,9 +69,6 @@ scoped_refptr<gl::GLShareGroup> GetShareGroup() override; private: - void CreateSequenceOnThread(std::unique_ptr<SingleTaskSequence>* sequence, - base::WaitableEvent* completion); - GpuInProcessThreadServiceDelegate* const delegate_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; Scheduler* scheduler_;
diff --git a/gpu/ipc/scheduler_sequence.cc b/gpu/ipc/scheduler_sequence.cc index 16dbb85..11fedf5 100644 --- a/gpu/ipc/scheduler_sequence.cc +++ b/gpu/ipc/scheduler_sequence.cc
@@ -44,10 +44,13 @@ #endif } -SchedulerSequence::SchedulerSequence(Scheduler* scheduler) +SchedulerSequence::SchedulerSequence( + Scheduler* scheduler, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) : SingleTaskSequence(), scheduler_(scheduler), - sequence_id_(scheduler->CreateSequence(SchedulingPriority::kHigh)) {} + sequence_id_(scheduler->CreateSequence(SchedulingPriority::kHigh, + std::move(task_runner))) {} // Note: this drops tasks not executed yet. SchedulerSequence::~SchedulerSequence() {
diff --git a/gpu/ipc/scheduler_sequence.h b/gpu/ipc/scheduler_sequence.h index 6745c9c1..effb371e 100644 --- a/gpu/ipc/scheduler_sequence.h +++ b/gpu/ipc/scheduler_sequence.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/check_op.h" #include "base/macros.h" +#include "base/single_thread_task_runner.h" #include "gpu/command_buffer/common/sync_token.h" #include "gpu/command_buffer/service/sequence_id.h" #include "gpu/ipc/gl_in_process_context_export.h" @@ -62,7 +63,8 @@ // allow ScheduleTask. static void DefaultDisallowScheduleTaskOnCurrentThread(); - explicit SchedulerSequence(Scheduler* scheduler); + SchedulerSequence(Scheduler* scheduler, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); // Note: this drops tasks not executed yet. ~SchedulerSequence() override;
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc index f3909c0..69bcfd5 100644 --- a/gpu/ipc/service/gpu_channel.cc +++ b/gpu/ipc/service/gpu_channel.cc
@@ -903,7 +903,8 @@ SequenceId sequence_id = stream_sequences_[stream_id]; if (sequence_id.is_null()) { - sequence_id = scheduler_->CreateSequence(init_params->stream_priority); + sequence_id = + scheduler_->CreateSequence(init_params->stream_priority, task_runner_); stream_sequences_[stream_id] = sequence_id; }
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.cc b/gpu/ipc/service/image_decode_accelerator_stub.cc index 7559c7e..5c39728 100644 --- a/gpu/ipc/service/image_decode_accelerator_stub.cc +++ b/gpu/ipc/service/image_decode_accelerator_stub.cc
@@ -99,7 +99,8 @@ int32_t route_id) : worker_(worker), channel_(channel), - sequence_(channel->scheduler()->CreateSequence(SchedulingPriority::kLow)), + sequence_(channel->scheduler()->CreateSequence(SchedulingPriority::kLow, + channel->task_runner())), sync_point_client_state_( channel->sync_point_manager()->CreateSyncPointClientState( CommandBufferNamespace::GPU_IO,
diff --git a/gpu/ipc/service/image_transport_surface_win.cc b/gpu/ipc/service/image_transport_surface_win.cc index a3a0937..916ac85 100644 --- a/gpu/ipc/service/image_transport_surface_win.cc +++ b/gpu/ipc/service/image_transport_surface_win.cc
@@ -34,6 +34,8 @@ settings.force_root_surface_full_damage = features::IsUsingSkiaRenderer() && gl::ShouldForceDirectCompositionRootSurfaceFullDamage(); + settings.force_root_surface_full_damage_always = + workarounds.force_direct_composition_full_damage_always; return settings; } } // namespace
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc index d52d07d..0ebfe75 100644 --- a/gpu/ipc/service/shared_image_stub.cc +++ b/gpu/ipc/service/shared_image_stub.cc
@@ -31,7 +31,8 @@ : channel_(channel), command_buffer_id_( CommandBufferIdFromChannelAndRoute(channel->client_id(), route_id)), - sequence_(channel->scheduler()->CreateSequence(SchedulingPriority::kLow)), + sequence_(channel->scheduler()->CreateSequence(SchedulingPriority::kLow, + channel_->task_runner())), sync_point_client_state_( channel->sync_point_manager()->CreateSyncPointClientState( CommandBufferNamespace::GPU_IO,
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc index 6a3c3f7..7d4d68c3 100644 --- a/gpu/ipc/service/stream_texture_android.cc +++ b/gpu/ipc/service/stream_texture_android.cc
@@ -94,8 +94,8 @@ route_id_(route_id), has_listener_(false), context_state_(std::move(context_state)), - sequence_( - channel_->scheduler()->CreateSequence(SchedulingPriority::kLow)), + sequence_(channel_->scheduler()->CreateSequence(SchedulingPriority::kLow, + channel_->task_runner())), sync_point_client_state_( channel_->sync_point_manager()->CreateSyncPointClientState( CommandBufferNamespace::GPU_IO,
diff --git a/gpu/vulkan/vulkan_surface.cc b/gpu/vulkan/vulkan_surface.cc index d5b8097..94355f2 100644 --- a/gpu/vulkan/vulkan_surface.cc +++ b/gpu/vulkan/vulkan_surface.cc
@@ -8,9 +8,9 @@ #include <algorithm> +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/macros.h" -#include "base/stl_util.h" #include "base/threading/scoped_blocking_call.h" #include "gpu/vulkan/vulkan_device_queue.h" #include "gpu/vulkan/vulkan_function_pointers.h"
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 0348334..904689d 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -187,14 +187,26 @@ sources = [ "first_run_app_state_agent.h", "first_run_app_state_agent.mm", + "first_run_app_state_agent_testing.h", ] deps = [ + ":tests_hook", "//base", + "//ios/chrome/app:blocking_scene_commands", "//ios/chrome/app/application_delegate:app_state_header", "//ios/chrome/app/application_delegate:application_delegate_internal", + "//ios/chrome/browser", + "//ios/chrome/browser/browsing_data", + "//ios/chrome/browser/geolocation", + "//ios/chrome/browser/policy", "//ios/chrome/browser/ui:feature_flags", + "//ios/chrome/browser/ui/blocking_overlay", + "//ios/chrome/browser/ui/browser_view", + "//ios/chrome/browser/ui/commands:commands", + "//ios/chrome/browser/ui/first_run", + "//ios/chrome/browser/ui/first_run:field_trial", "//ios/chrome/browser/ui/first_run:utils", - "//ios/chrome/browser/ui/main:main", + "//ios/chrome/browser/ui/main:browser_interface_provider", "//ios/chrome/browser/ui/main:observing_scene_agent", "//ios/chrome/browser/ui/main:scene", ]
diff --git a/ios/chrome/app/first_run_app_state_agent.h b/ios/chrome/app/first_run_app_state_agent.h index bd83dcf..cd53d56 100644 --- a/ios/chrome/app/first_run_app_state_agent.h +++ b/ios/chrome/app/first_run_app_state_agent.h
@@ -12,7 +12,6 @@ // App state agent that displays the first run UI when needed and handles the // InitStageFirstRun stage. @interface FirstRunAppAgent : NSObject <AppStateAgent> - @end #endif // IOS_CHROME_APP_FIRST_RUN_APP_STATE_AGENT_H_
diff --git a/ios/chrome/app/first_run_app_state_agent.mm b/ios/chrome/app/first_run_app_state_agent.mm index b3e83a7..cc9fa4a 100644 --- a/ios/chrome/app/first_run_app_state_agent.mm +++ b/ios/chrome/app/first_run_app_state_agent.mm
@@ -5,30 +5,71 @@ #import "ios/chrome/app/first_run_app_state_agent.h" #import "base/logging.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/app_state_observer.h" #include "ios/chrome/app/application_delegate/startup_information.h" -#include "ios/chrome/browser/ui/first_run/first_run_util.h" +#import "ios/chrome/app/tests_hook.h" +#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h" +#import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/policy/policy_watcher_browser_agent.h" +#import "ios/chrome/browser/policy/policy_watcher_browser_agent_observer_bridge.h" +#import "ios/chrome/browser/ui/browser_view/browser_view_controller.h" +#import "ios/chrome/browser/ui/commands/browsing_data_commands.h" +#import "ios/chrome/browser/ui/commands/command_dispatcher.h" +#import "ios/chrome/browser/ui/first_run/first_run_util.h" +#import "ios/chrome/browser/ui/first_run/location_permissions_field_trial.h" +#import "ios/chrome/browser/ui/first_run/orientation_limiting_navigation_controller.h" +#import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h" +#import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/main/scene_controller.h" #import "ios/chrome/browser/ui/main/scene_state.h" #import "ios/chrome/browser/ui/main/scene_state_observer.h" +#import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface FirstRunAppAgent () <AppStateObserver> +namespace { +// Histogram enum values for showing the experiment arms of the location +// permissions experiment. These values are persisted to logs. Entries should +// not be renumbered and numeric values should never be reused. +enum class LocationPermissionsUI { + // The First Run native location prompt was not shown. + kFirstRunPromptNotShown = 0, + // The First Run location permissions modal was shown. + kFirstRunModal = 1, + // kMaxValue should share the value of the highest enumerator. + kMaxValue = kFirstRunModal, +}; +} + +@interface FirstRunAppAgent () <AppStateObserver, + PolicyWatcherBrowserAgentObserving> // The app state for the app. @property(nonatomic, weak, readonly) AppState* appState; +@property(nonatomic, weak) + WelcomeToChromeViewController* welcomeToChromeController; + // The scene that is chosen for presenting the FRE on. @property(nonatomic, strong) SceneState* presentingSceneState; @end -@implementation FirstRunAppAgent +@implementation FirstRunAppAgent { + // UI blocker used while the FRE UI is shown in the scene controlled by this + // object. + std::unique_ptr<ScopedUIBlocker> _firstRunUIBlocker; + + // Observer for the sign-out policy changes. + std::unique_ptr<PolicyWatcherBrowserAgentObserverBridge> + _policyWatcherObserverBridge; +} - (void)dealloc { [_appState removeObserver:self]; @@ -76,7 +117,7 @@ return; } - [self showFirstRun:self.presentingSceneState]; + [self showFirstRunUI]; } - (void)appState:(AppState*)appState @@ -94,21 +135,175 @@ return; } - [self showFirstRun:sceneState]; + [self showFirstRunUI]; } #pragma mark - internal -- (void)showFirstRun:(SceneState*)sceneState { - DCHECK(self.appState.initStage == InitStageFirstRun); +- (void)setUpPolicyWatcher { + _policyWatcherObserverBridge = + std::make_unique<PolicyWatcherBrowserAgentObserverBridge>(self); + + Browser* mainBrowser = + self.presentingSceneState.interfaceProvider.mainInterface.browser; + PolicyWatcherBrowserAgent* policyWatcherAgent = + PolicyWatcherBrowserAgent::FromBrowser(mainBrowser); + + // Sanity check that there is a PolicyWatcherBrowserAgent agent stashed in + // the browser. This considers that the main browser for the scene was + // initialized before showing the FRE, which should always be the case. + DCHECK(policyWatcherAgent); + + policyWatcherAgent->AddObserver(_policyWatcherObserverBridge.get()); +} + +- (void)tearDownPolicyWatcher { + PolicyWatcherBrowserAgent::FromBrowser( + self.presentingSceneState.interfaceProvider.mainInterface.browser) + ->RemoveObserver(_policyWatcherObserverBridge.get()); +} + +- (void)showFirstRunUI { + if (![self ignoreFirstRunStageForTesting]) { + DCHECK(self.appState.initStage == InitStageFirstRun); + } + // There must be a designated presenting scene before showing the first run // UI. DCHECK(self.presentingSceneState); + [self setUpPolicyWatcher]; + if (base::FeatureList::IsEnabled(kEnableFREUIModuleIOS)) { - [sceneState.controller showFirstRunUI]; + [self.presentingSceneState.controller showFirstRunUI]; } else { - [sceneState.controller showLegacyFirstRunUI]; + [self showLegacyFirstRunUI]; + } +} + +// Presents the first run UI to the user. +- (void)showLegacyFirstRunUI { + DCHECK(![self.presentingSceneState.controller isPresentingSigninView]); + + // This should not be necessary because now it's an app-level object doing + // this. + DCHECK(!_firstRunUIBlocker); + _firstRunUIBlocker = + std::make_unique<ScopedUIBlocker>(self.presentingSceneState); + // Register for the first run dismissal notification to reset + // |sceneState.presentingFirstRunUI| flag; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleFirstRunUIWillFinish) + name:kChromeFirstRunUIWillFinishNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleFirstRunUIDidFinish) + name:kChromeFirstRunUIDidFinishNotification + object:nil]; + + Browser* browser = + self.presentingSceneState.interfaceProvider.mainInterface.browser; + id<ApplicationCommands, BrowsingDataCommands> welcomeHandler = + static_cast<id<ApplicationCommands, BrowsingDataCommands>>( + browser->GetCommandDispatcher()); + + WelcomeToChromeViewController* welcomeToChrome = + [[WelcomeToChromeViewController alloc] + initWithBrowser:browser + presenter:self.presentingSceneState.interfaceProvider + .currentInterface.bvc + dispatcher:welcomeHandler]; + self.welcomeToChromeController = welcomeToChrome; + UINavigationController* navController = + [[OrientationLimitingNavigationController alloc] + initWithRootViewController:welcomeToChrome]; + [navController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; + navController.modalPresentationStyle = UIModalPresentationFullScreen; + CGRect appFrame = [[UIScreen mainScreen] bounds]; + [[navController view] setFrame:appFrame]; + self.presentingSceneState.presentingFirstRunUI = YES; + [self.presentingSceneState.interfaceProvider.currentInterface.viewController + presentViewController:navController + animated:NO + completion:nil]; +} + +- (void)handleFirstRunUIWillFinish { + DCHECK(self.presentingSceneState.presentingFirstRunUI); + _firstRunUIBlocker.reset(); + self.presentingSceneState.presentingFirstRunUI = NO; + [self tearDownPolicyWatcher]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:kChromeFirstRunUIWillFinishNotification + object:nil]; +} + +// All of this can be triggered from will transition from init stage, or did +// transition to init stage, once the rest is done. +- (void)handleFirstRunUIDidFinish { + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:kChromeFirstRunUIDidFinishNotification + object:nil]; + + self.welcomeToChromeController = nil; + + [self maybePromptLocationWithSystemAlert]; + + if (![self ignoreFirstRunStageForTesting]) { + [self.appState queueTransitionToNextInitStage]; + } +} + +- (void)logLocationPermissionsExperimentForGroupShown: + (LocationPermissionsUI)experimentGroup { + UMA_HISTOGRAM_ENUMERATION("IOS.LocationPermissionsUI", experimentGroup); +} + +- (void)maybePromptLocationWithSystemAlert { + if (!location_permissions_field_trial::IsInRemoveFirstRunPromptGroup() && + !location_permissions_field_trial::IsInFirstRunModalGroup()) { + [self logLocationPermissionsExperimentForGroupShown: + LocationPermissionsUI::kFirstRunPromptNotShown]; + // As soon as First Run has finished, give OmniboxGeolocationController an + // opportunity to present the iOS system location alert. + [[OmniboxGeolocationController sharedInstance] triggerSystemPrompt]; + } else if (location_permissions_field_trial:: + IsInRemoveFirstRunPromptGroup()) { + // If in RemoveFirstRunPrompt group, the system prompt will be delayed until + // the site requests location information. + [[OmniboxGeolocationController sharedInstance] + systemPromptSkippedForNewUser]; + } +} + +// TODO(crbug.com/1210246): Remove this hook once the chrome test fixture is +// adapted to startup testing. +// +// Determines whether the First Run stage has to be ignored because of +// testing. When testing with first_run_egtest.mm, the First Run UI is +// manually triggered after the browser is fully initialized, in which +// case the code that assumes that the app is in the First Run stage when +// showing the FRE has to be ignored to avoid unexepted failures (e.g., DCHECKs, +// unexpected init stage transition). +- (BOOL)ignoreFirstRunStageForTesting { + return tests_hook::DisableFirstRun(); +} + +#pragma mark - PolicyWatcherBrowserAgentObserving + +- (void)policyWatcherBrowserAgentNotifySignInDisabled: + (PolicyWatcherBrowserAgent*)policyWatcher { + auto signinInterrupted = ^{ + policyWatcher->SignInUIDismissed(); + }; + + if (self.welcomeToChromeController) { + [self.welcomeToChromeController + interruptSigninCoordinatorWithCompletion:signinInterrupted]; } }
diff --git a/ios/chrome/app/first_run_app_state_agent_testing.h b/ios/chrome/app/first_run_app_state_agent_testing.h new file mode 100644 index 0000000..b660352 --- /dev/null +++ b/ios/chrome/app/first_run_app_state_agent_testing.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_APP_FIRST_RUN_APP_STATE_AGENT_TESTING_H_ +#define IOS_CHROME_APP_FIRST_RUN_APP_STATE_AGENT_TESTING_H_ + +#import "ios/chrome/app/first_run_app_state_agent.h" + +// Interface for testing FirstRunAppAgent. +@interface FirstRunAppAgent (TestingOnly) + +// TODO(crbug.com/1210246): Remove this once the chrome test fixture is adapted +// to startup testing. +// Shows the First Run UI for testing purpose. +- (void)showFirstRunUI; + +@end + +#endif // IOS_CHROME_APP_FIRST_RUN_APP_STATE_AGENT_TESTING_H_
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 32f4805..5a7e2c1b 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -289,6 +289,8 @@ // List of closure to run as part of shutdown. The closure will be called // in reverse order of registration. std::vector<base::OnceClosure> _cleanupClosures; + + FirstRunAppAgent* _firstRunAppAgent; } // Handles collecting metrics on user triggered screenshots @@ -644,7 +646,10 @@ - (void)addPostSafeModeAgents { [self.appState addAgent:[[ContentSuggestionsSchedulerAppAgent alloc] init]]; [self.appState addAgent:[[IncognitoUsageAppStateAgent alloc] init]]; - [self.appState addAgent:[[FirstRunAppAgent alloc] init]]; + + FirstRunAppAgent* firstRunAppAgent = [[FirstRunAppAgent alloc] init]; + _firstRunAppAgent = firstRunAppAgent; + [self.appState addAgent:firstRunAppAgent]; } #pragma mark - Property implementation. @@ -1290,6 +1295,10 @@ @implementation MainController (TestingOnly) +- (FirstRunAppAgent*)firstRunAppAgent { + return _firstRunAppAgent; +} + - (void)setStartupParametersWithURL:(const GURL&)launchURL { NSString* sourceApplication = @"Fake App"; SceneState* sceneState = self.appState.foregroundActiveScene;
diff --git a/ios/chrome/app/main_controller_private.h b/ios/chrome/app/main_controller_private.h index 1550252..88237cf 100644 --- a/ios/chrome/app/main_controller_private.h +++ b/ios/chrome/app/main_controller_private.h
@@ -13,6 +13,7 @@ class GURL; @protocol TabSwitcher; +@class FirstRunAppAgent; // Private methods and protocols that are made visible here for tests. @interface MainController () @@ -25,6 +26,11 @@ // Methods that only exist for tests. @interface MainController (TestingOnly) +// TODO(crbug.com/1210246): Remove this once the chrome test fixture is adapted +// to startup testing. +// Returns the FirstRunAppAgent. +- (FirstRunAppAgent*)firstRunAppAgent; + // Sets the internal startup state to indicate that the launch was triggered // by an external app opening the given URL. - (void)setStartupParametersWithURL:(const GURL&)launchURL;
diff --git a/ios/chrome/browser/translate/language_detection_javascript_unittest.mm b/ios/chrome/browser/translate/language_detection_javascript_unittest.mm index ed91175..c78b04a 100644 --- a/ios/chrome/browser/translate/language_detection_javascript_unittest.mm +++ b/ios/chrome/browser/translate/language_detection_javascript_unittest.mm
@@ -59,10 +59,10 @@ }); } - // Verifies if translation was allowed or not on the page based on + // Verifies if the notranslate meta tag is present or not on the page based on // |expected_value|. - void ExpectTranslationAllowed(BOOL expected_value) { - InjectJsAndVerify(@"__gCrWeb.languageDetection.translationAllowed();", + void ExpectHasNoTranslate(BOOL expected_value) { + InjectJsAndVerify(@"__gCrWeb.languageDetection.hasNoTranslate();", @(expected_value)); } @@ -91,20 +91,20 @@ } }; -// Tests |__gCrWeb.languageDetection.translationAllowed| JS call. -TEST_F(JsLanguageDetectionManagerTest, IsTranslationAllowed) { +// Tests |__gCrWeb.languageDetection.hasNoTranslate| JS call. +TEST_F(JsLanguageDetectionManagerTest, PageHasNoTranslate) { LoadHtml(@"<html></html>"); - ExpectTranslationAllowed(YES); + ExpectHasNoTranslate(NO); LoadHtml(@"<html><head>" "<meta name='google' content='notranslate'>" "</head></html>"); - ExpectTranslationAllowed(NO); + ExpectHasNoTranslate(YES); LoadHtml(@"<html><head>" "<meta name='google' value='notranslate'>" "</head></html>"); - ExpectTranslationAllowed(NO); + ExpectHasNoTranslate(YES); } // Tests correctness of |document.documentElement.lang| attribute. @@ -261,11 +261,16 @@ base::CallbackListSubscription subscription_; }; -// Tests if |__gCrWeb.languageDetection.detectLanguage| correctly informs the -// native side when translation is not allowed. +// Tests if |__gCrWeb.languageDetection.hasNoTranslate| correctly informs the +// native side when the notranslate meta tag is specified. TEST_F(JsLanguageDetectionManagerDetectLanguageTest, - DetectLanguageTranslationNotAllowed) { - LoadHtml(@"<html></html>"); + DetectLanguageWithNoTranslateMeta) { + // A simple page using the notranslate meta tag. + NSString* html = @"<html><head>" + @"<meta http-equiv='content-language' content='en'>" + @"<meta name='google' content='notranslate'>" + @"</head></html>"; + LoadHtml(html); ExecuteJavaScript(@"__gCrWeb.languageDetection.detectLanguage()"); // Wait until the original injection has received a command. base::test::ios::WaitUntilCondition(^bool() { @@ -275,30 +280,25 @@ commands_received_.clear(); - // Stub out translationAllowed. - NSString* const kTranslationAllowedJS = - @"__gCrWeb.languageDetection.translationAllowed = function() {" - @" return false;" - @"}"; - ExecuteJavaScript(kTranslationAllowedJS); - ConditionBlock commands_recieved_block = ^bool { - return commands_received_.size(); - }; - InjectJSAndWaitUntilCondition(@"__gCrWeb.languageDetection.detectLanguage()", - commands_recieved_block); + ExecuteJavaScript(@"__gCrWeb.languageDetection.detectLanguage()"); + base::test::ios::WaitUntilCondition(^bool() { + return !commands_received_.empty(); + }); ASSERT_EQ(1U, commands_received_.size()); const base::Value& value = commands_received_[0]; - absl::optional<bool> translation_allowed = - value.FindBoolKey("translationAllowed"); - ASSERT_TRUE(translation_allowed); - EXPECT_FALSE(*translation_allowed); + absl::optional<bool> has_notranslate = value.FindBoolKey("hasNoTranslate"); + ASSERT_TRUE(has_notranslate); + EXPECT_TRUE(value.FindKey("captureTextTime")); + EXPECT_TRUE(value.FindKey("htmlLang")); + EXPECT_TRUE(value.FindKey("httpContentLanguage")); + EXPECT_TRUE(*has_notranslate); } // Tests if |__gCrWeb.languageDetection.detectLanguage| correctly informs the -// native side when translation is allowed with the right parameters. +// native side when no notranslate meta tag is specified. TEST_F(JsLanguageDetectionManagerDetectLanguageTest, - DetectLanguageTranslationAllowed) { - // A simple page that allows translation. + DetectLanguageWithoutNoTranslateMeta) { + // A simple page with no notranslate meta tag. NSString* html = @"<html><head>" @"<meta http-equiv='content-language' content='en'>" @"</head></html>"; @@ -319,12 +319,11 @@ ASSERT_EQ(1U, commands_received_.size()); const base::Value& value = commands_received_[0]; - absl::optional<bool> translation_allowed = - value.FindBoolKey("translationAllowed"); + absl::optional<bool> has_notranslate = value.FindBoolKey("hasNoTranslate"); - ASSERT_TRUE(translation_allowed); + ASSERT_TRUE(has_notranslate); EXPECT_TRUE(value.FindKey("captureTextTime")); EXPECT_TRUE(value.FindKey("htmlLang")); EXPECT_TRUE(value.FindKey("httpContentLanguage")); - EXPECT_TRUE(*translation_allowed); + EXPECT_FALSE(*has_notranslate); }
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn index 4fe567a..29ef22d 100644 --- a/ios/chrome/browser/ui/first_run/BUILD.gn +++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -223,6 +223,7 @@ "//components/metrics", "//components/prefs", "//ios/chrome/app:app_internal", + "//ios/chrome/app:first_run_app_state_agent", "//ios/chrome/browser", "//ios/chrome/browser/sync", "//ios/chrome/browser/ui/main:scene",
diff --git a/ios/chrome/browser/ui/first_run/first_run_app_interface.h b/ios/chrome/browser/ui/first_run/first_run_app_interface.h index ab7b2c9..15c1c95 100644 --- a/ios/chrome/browser/ui/first_run/first_run_app_interface.h +++ b/ios/chrome/browser/ui/first_run/first_run_app_interface.h
@@ -13,7 +13,7 @@ @interface FirstRunAppInterface : NSObject // Triggers the display of the first run UI. -+ (void)showLegacyFirstRunUI; ++ (void)showFirstRunUI; // Resets the UMA collection enabled pref to |enabled|. + (void)setUMACollectionEnabled:(BOOL)enabled;
diff --git a/ios/chrome/browser/ui/first_run/first_run_app_interface.mm b/ios/chrome/browser/ui/first_run/first_run_app_interface.mm index 7c8c592..92b0b26 100644 --- a/ios/chrome/browser/ui/first_run/first_run_app_interface.mm +++ b/ios/chrome/browser/ui/first_run/first_run_app_interface.mm
@@ -7,7 +7,10 @@ #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_reporting_default_state.h" #include "components/prefs/pref_service.h" +#include "ios/chrome/app/first_run_app_state_agent_testing.h" #import "ios/chrome/app/main_controller.h" +#include "ios/chrome/app/main_controller.h" +#import "ios/chrome/app/main_controller_private.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/sync/sync_setup_service.h" #include "ios/chrome/browser/sync/sync_setup_service_factory.h" @@ -22,8 +25,8 @@ @implementation FirstRunAppInterface -+ (void)showLegacyFirstRunUI { - [chrome_test_util::GetForegroundActiveSceneController() showLegacyFirstRunUI]; ++ (void)showFirstRunUI { + [[chrome_test_util::GetMainController() firstRunAppAgent] showFirstRunUI]; } + (void)setUMACollectionEnabled:(BOOL)enabled {
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm index b4f9b82..abaa8d4 100644 --- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm +++ b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
@@ -63,12 +63,13 @@ - (AppLaunchConfiguration)appConfigurationForTestCase { AppLaunchConfiguration config; config.features_disabled.push_back(kLocationPermissionsPrompt); + config.features_disabled.push_back(kEnableFREUIModuleIOS); return config; } // Navigates to the terms of service and back. - (void)testTermsAndConditions { - [FirstRunAppInterface showLegacyFirstRunUI]; + [FirstRunAppInterface showFirstRunUI]; id<GREYMatcher> termsOfServiceLink = grey_accessibilityLabel(@"Terms of Service"); @@ -101,7 +102,7 @@ // Toggle the UMA checkbox. - (void)testToggleMetricsOn { - [FirstRunAppInterface showLegacyFirstRunUI]; + [FirstRunAppInterface showFirstRunUI]; id<GREYMatcher> metrics = grey_accessibilityID(first_run::kUMAMetricsButtonAccessibilityIdentifier); @@ -122,7 +123,7 @@ // Dismisses the first run screens. - (void)testDismissFirstRun { - [FirstRunAppInterface showLegacyFirstRunUI]; + [FirstRunAppInterface showFirstRunUI]; [[EarlGrey selectElementWithMatcher:FirstRunOptInAcceptButton()] performAction:grey_tap()]; @@ -144,7 +145,7 @@ [SigninEarlGrey addFakeIdentity:fakeIdentity]; // Launch First Run and accept tems of services. - [FirstRunAppInterface showLegacyFirstRunUI]; + [FirstRunAppInterface showFirstRunUI]; [[EarlGrey selectElementWithMatcher:FirstRunOptInAcceptButton()] performAction:grey_tap()]; @@ -170,7 +171,7 @@ if (![ChromeEarlGrey areMultipleWindowsSupported]) EARL_GREY_TEST_DISABLED(@"Multiple windows can't be opened."); - [FirstRunAppInterface showLegacyFirstRunUI]; + [FirstRunAppInterface showFirstRunUI]; [ChromeEarlGrey openNewWindow]; [ChromeEarlGrey waitForForegroundWindowCount:2];
diff --git a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm index bf968f3..aa7d856 100644 --- a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm +++ b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
@@ -300,8 +300,8 @@ translate::kUnknownLanguageCode)]; } -// Tests that language detection is not performed when the page specifies that -// it should not be translated. +// Tests that language detection is still performed when the page specifies the +// notranslate meta tag. - (void)testLanguageDetectionNoTranslate { // Start the HTTP server. std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider); @@ -315,16 +315,16 @@ // Load some french page with |content="notranslate"| meta tag. [ChromeEarlGrey loadURL:noTranslateContentURL]; - // Check that no language has been detected. - GREYAssertFalse([self waitForLanguageDetection], - @"A language has been detected"); + // Check that the language has been detected. + GREYAssertTrue([self waitForLanguageDetection], + @"A language has been detected"); // Load some french page with |value="notranslate"| meta tag. [ChromeEarlGrey loadURL:noTranslateValueURL]; - // Check that no language has been detected. - GREYAssertFalse([self waitForLanguageDetection], - @"A language has been detected"); + // Check that the language has been detected. + GREYAssertTrue([self waitForLanguageDetection], + @"A language has been detected"); } // Tests that history.pushState triggers a new detection.
diff --git a/ios/chrome/browser/ui/main/scene_controller.h b/ios/chrome/browser/ui/main/scene_controller.h index 146dc90..f7fb10b 100644 --- a/ios/chrome/browser/ui/main/scene_controller.h +++ b/ios/chrome/browser/ui/main/scene_controller.h
@@ -33,22 +33,21 @@ @property(nonatomic, strong, readonly) id<BrowserInterfaceProvider> interfaceProvider; +// YES if incognito mode is forced by enterprise policy. +@property(nonatomic, readonly, getter=isIncognitoForced) BOOL incognitoForced; + +// YES if the scene is presenting the signin view. +@property(nonatomic, readonly) BOOL isPresentingSigninView; + // Handler for the UIWindowSceneDelegate callback with the same selector. - (void)performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler API_AVAILABLE(ios(13)); -// Return YES if incognito mode is forced by enterprise policy. -- (BOOL)isIncognitoForced; - // TODO(crbug.com/1210256): Remove this once it is migrated to the agent. // Shows the new first run UI. - (void)showFirstRunUI; -// TODO(crbug.com/1210256): Remove this once it is migrated to the agent. -// Shows the legacy first run UI. -- (void)showLegacyFirstRunUI; - @end #endif // IOS_CHROME_BROWSER_UI_MAIN_SCENE_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 1e5ab32..1b8e7db 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -382,6 +382,10 @@ } } +- (BOOL)isPresentingSigninView { + return self.signinCoordinator != nil; +} + #pragma mark - SceneStateObserver - (void)sceneState:(SceneState*)sceneState @@ -835,7 +839,8 @@ // Only create the restoration helper if the session with the current session // id was backed up successfully. - if (self.sceneState.appState.sessionRestorationRequired) { + if (self.sceneState.appState.sessionRestorationRequired && + !self.sceneState.appState.startupInformation.isFirstRun) { Browser* mainBrowser = self.mainInterface.browser; if (!base::ios::IsMultiwindowSupported() || [CrashRestoreHelper @@ -1162,48 +1167,6 @@ #pragma mark - First Run -// Initializes the first run UI and presents it to the user. -- (void)showLegacyFirstRunUI { - DCHECK(!self.signinCoordinator); - DCHECK(!_firstRunUIBlocker); - _firstRunUIBlocker = std::make_unique<ScopedUIBlocker>(self.sceneState); - // Register for the first run dismissal notification to reset - // |sceneState.presentingFirstRunUI| flag; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(handleFirstRunUIWillFinish) - name:kChromeFirstRunUIWillFinishNotification - object:nil]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(handleFirstRunUIDidFinish) - name:kChromeFirstRunUIDidFinishNotification - object:nil]; - - Browser* browser = self.mainInterface.browser; - id<ApplicationCommands, BrowsingDataCommands> welcomeHandler = - static_cast<id<ApplicationCommands, BrowsingDataCommands>>( - browser->GetCommandDispatcher()); - - WelcomeToChromeViewController* welcomeToChrome = - [[WelcomeToChromeViewController alloc] - initWithBrowser:browser - presenter:self.currentInterface.bvc - dispatcher:welcomeHandler]; - self.welcomeToChromeController = welcomeToChrome; - UINavigationController* navController = - [[OrientationLimitingNavigationController alloc] - initWithRootViewController:welcomeToChrome]; - [navController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; - navController.modalPresentationStyle = UIModalPresentationFullScreen; - CGRect appFrame = [[UIScreen mainScreen] bounds]; - [[navController view] setFrame:appFrame]; - self.sceneState.presentingFirstRunUI = YES; - [self.currentInterface.viewController presentViewController:navController - animated:NO - completion:nil]; -} - // Shows the first run UI. - (void)showFirstRunUI { DCHECK(!_firstRunUIBlocker); @@ -1252,34 +1215,6 @@ object:nil]; } -// Handles the notification that first run modal dialog UI completed. -- (void)handleFirstRunUIDidFinish { - [[NSNotificationCenter defaultCenter] - removeObserver:self - name:kChromeFirstRunUIDidFinishNotification - object:nil]; - - self.welcomeToChromeController = nil; - - if (!location_permissions_field_trial::IsInRemoveFirstRunPromptGroup() && - !location_permissions_field_trial::IsInFirstRunModalGroup()) { - [self logLocationPermissionsExperimentForGroupShown: - LocationPermissionsUI::kFirstRunPromptNotShown]; - // As soon as First Run has finished, give OmniboxGeolocationController an - // opportunity to present the iOS system location alert. - [[OmniboxGeolocationController sharedInstance] triggerSystemPrompt]; - } else if (location_permissions_field_trial:: - IsInRemoveFirstRunPromptGroup()) { - // If in RemoveFirstRunPrompt group, the system prompt will be delayed until - // the site requests location information. - [[OmniboxGeolocationController sharedInstance] - systemPromptSkippedForNewUser]; - } - if (![self ignoreFirstRunStageForTesting]) { - [self.sceneState.appState queueTransitionToNextInitStage]; - } -} - // Presents the sign-in upgrade promo if is relevant and possible. // Returns YES if the promo is shown. - (BOOL)presentSigninUpgradePromoIfPossible { @@ -3154,10 +3089,6 @@ [self interruptSigninCoordinatorAnimated:YES completion:signinInterrupted]; UMA_HISTOGRAM_BOOLEAN( "Enterprise.BrowserSigninIOS.SignInInterruptedByPolicy", true); - } else if (self.sceneState.presentingFirstRunUI && - self.welcomeToChromeController) { - [self.welcomeToChromeController - interruptSigninCoordinatorWithCompletion:signinInterrupted]; } }
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm index f83d94b..df1fc1c 100644 --- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm +++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
@@ -714,7 +714,7 @@ IDS_IOS_GOOGLE_SERVICES_SETTINGS_AUTOCOMPLETE_SEARCHES_AND_URLS_TEXT detailStringID: IDS_IOS_GOOGLE_SERVICES_SETTINGS_AUTOCOMPLETE_SEARCHES_AND_URLS_DETAIL - status:self.autocompleteSearchPreference]; + status:self.autocompleteSearchPreference.value]; [items addObject:autocompleteItem]; } else { SyncSwitchItem* autocompleteItem = [self @@ -735,7 +735,7 @@ IDS_IOS_GOOGLE_SERVICES_SETTINGS_SAFE_BROWSING_TEXT detailStringID: IDS_IOS_GOOGLE_SERVICES_SETTINGS_SAFE_BROWSING_DETAIL - status:self.safeBrowsingPreference]; + status:self.safeBrowsingPreference.value]; [items addObject:safeBrowsingManagedItem]; } else { SyncSwitchItem* safeBrowsingItem = [self
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 0cb1c43..88c44227 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -1592,12 +1592,16 @@ googleSyncItem.iconImageName = kSyncAndGoogleServicesSyncOffImageName; break; } - case kSyncOff: - case kSyncEnabledWithNoSelectedTypes: { + case kSyncOff: { googleSyncItem.detailText = l10n_util::GetNSString(IDS_IOS_SETTING_OFF); googleSyncItem.iconImageName = kSyncAndGoogleServicesSyncOffImageName; break; } + case kSyncEnabledWithNoSelectedTypes: { + googleSyncItem.detailText = nil; + googleSyncItem.iconImageName = kSyncAndGoogleServicesSyncOffImageName; + break; + } case kSyncEnabledWithError: { SyncSetupService* syncSetupService = SyncSetupServiceFactory::GetForBrowserState(_browserState);
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller_mice_unittest.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller_mice_unittest.mm index b4454fb..4bbe7b2 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller_mice_unittest.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller_mice_unittest.mm
@@ -236,9 +236,10 @@ sync_item.detailText); } -// Verifies that the Sync icon displays the off state when the user has -// completed the sign-in and sync flow then explcitly turned off all data types -// in the Sync settings. +// Verifies that the Sync icon displays the off state (and no detail text) when +// the user has completed the sign-in and sync flow then explcitly turned off +// all data types in the Sync settings. +// This case can only happen for pre-MICE users who migrated with MICE. TEST_F(SettingsTableViewControllerMICETest, DisablesAllSyncSettingsAfterFirstSetup) { ON_CALL(*sync_service_mock_->GetMockUserSettings(), GetSelectedTypes()) @@ -261,6 +262,5 @@ static_cast<TableViewDetailIconItem*>(account_items[1]); ASSERT_NSEQ(l10n_util::GetNSString(IDS_IOS_GOOGLE_SYNC_SETTINGS_TITLE), sync_item.text); - ASSERT_NSEQ(l10n_util::GetNSString(IDS_IOS_SETTING_OFF), - sync_item.detailText); + ASSERT_EQ(nil, sync_item.detailText); }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 index e3f410d..49297ac9 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -74f26b6069b4e8166fab915ffcaf9df3ca65f2bc \ No newline at end of file +a74cc9413758120b7bc2f7c0ecd4e992128f2609 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 index 8dc1409..514af577 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -9afa9743ed0d528ee1d07e03f556734fd81b87c5 \ No newline at end of file +5afe4773af8dc6bb2c95769478f413f5a1be81c5 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 index 4550cbe4..c0a5cdb 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -63ef4ffa6d0c6bd613de7f1011696a61ac3cc539 \ No newline at end of file +86e71244c37d9693bf9687ff78eb2b523ea48bcd \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 index de93bcf..c458979 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -c3e99ca14823c5ec0fb32cbddff8653ece7e1b75 \ No newline at end of file +bec573cefb452413f030cc3c8505b19836df8de9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 index 535a4e8..2a015e8 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -66b6e4106a979ba78d7e6d2c5f03399b9e4a3e6f \ No newline at end of file +1a8f6a4560d9d2f95034a69d5bcf33f39767cd74 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 index d34ab3e..d6b7730 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -720152502285633607d3229421db879f14a2a0be \ No newline at end of file +a71129e8bed9af8e877e580cfbdb9a34734dc906 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 index c3dd7e7..1051648 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -a50b8d176d51c429635dfb2d99729d3049585ff6 \ No newline at end of file +a613af75638e18aa756ffa4bf3f9567a248014bf \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 index 1d69676..2e4a1df 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -b6aaeb512599cc9b412e9629bad47da704aebd81 \ No newline at end of file +9658304b579055f7a3fd328e820c9337319ea597 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 index 485a7675..5f5c3882 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -2630343a8c71f8b5b614eda3b9ab4c9d79eebddd \ No newline at end of file +067f45484084e17ea599214e896b63462cdea0e3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 index c9c8f74..01ec24af 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -e3b951ad1079099f2d8a6d73dec57e98b401202b \ No newline at end of file +c85d87c12e09e4b0bb238ddb3fa762b0ac42df22 \ No newline at end of file
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc index bdb19d6..16f7058 100644 --- a/ipc/ipc_channel_mojo.cc +++ b/ipc/ipc_channel_mojo.cc
@@ -186,21 +186,31 @@ } bool ChannelMojo::Connect() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - WillConnect(); - mojo::AssociatedRemote<mojom::Channel> sender; + mojo::PendingAssociatedRemote<mojom::Channel> sender; mojo::PendingAssociatedReceiver<mojom::Channel> receiver; bootstrap_->Connect(&sender, &receiver); DCHECK(!message_reader_); - sender->SetPeerPid(GetSelfPID()); message_reader_ = std::make_unique<internal::MessagePipeReader>( - pipe_, std::move(sender), std::move(receiver), this); + pipe_, std::move(sender), std::move(receiver), task_runner_, this); + + if (task_runner_->RunsTasksInCurrentSequence()) { + FinishConnectOnIOThread(); + } else { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&ChannelMojo::FinishConnectOnIOThread, weak_ptr_)); + } return true; } +void ChannelMojo::FinishConnectOnIOThread() { + DCHECK(message_reader_); + message_reader_->FinishInitializationOnIOThread(GetSelfPID()); +} + void ChannelMojo::Pause() { bootstrap_->Pause(); } @@ -375,6 +385,12 @@ const std::string& name, mojo::ScopedInterfaceEndpointHandle handle) { if (message_reader_) { + if (!task_runner_->RunsTasksInCurrentSequence()) { + message_reader_->thread_safe_sender().GetAssociatedInterface( + name, mojo::PendingAssociatedReceiver<mojom::GenericInterface>( + std::move(handle))); + return; + } message_reader_->GetRemoteInterface(name, std::move(handle)); } else { // Attach the associated interface to a disconnected pipe, so that the
diff --git a/ipc/ipc_channel_mojo.h b/ipc/ipc_channel_mojo.h index d99bb2f..3379466 100644 --- a/ipc/ipc_channel_mojo.h +++ b/ipc/ipc_channel_mojo.h
@@ -116,6 +116,8 @@ const std::string& name, mojo::ScopedInterfaceEndpointHandle handle) override; + void FinishConnectOnIOThread(); + base::WeakPtr<ChannelMojo> weak_ptr_; // A TaskRunner which runs tasks on the ChannelMojo's owning thread.
diff --git a/ipc/ipc_message_pipe_reader.cc b/ipc/ipc_message_pipe_reader.cc index eb290ab..8deecd3 100644 --- a/ipc/ipc_message_pipe_reader.cc +++ b/ipc/ipc_message_pipe_reader.cc
@@ -19,29 +19,83 @@ #include "base/trace_event/trace_event.h" #include "ipc/ipc_channel_mojo.h" #include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/thread_safe_proxy.h" namespace IPC { namespace internal { +namespace { + +class ThreadSafeProxy : public mojo::ThreadSafeProxy { + public: + using Forwarder = base::RepeatingCallback<void(mojo::Message)>; + + ThreadSafeProxy(scoped_refptr<base::SequencedTaskRunner> task_runner, + Forwarder forwarder, + mojo::AssociatedGroupController& group_controller) + : task_runner_(std::move(task_runner)), + forwarder_(std::move(forwarder)), + group_controller_(group_controller) {} + + // mojo::ThreadSafeProxy: + void SendMessage(mojo::Message& message) override { + message.SerializeHandles(&group_controller_); + task_runner_->PostTask(FROM_HERE, + base::BindOnce(forwarder_, std::move(message))); + } + + void SendMessageWithResponder( + mojo::Message& message, + std::unique_ptr<mojo::MessageReceiver> responder) override { + // We don't bother supporting this because it's not used in practice. + NOTREACHED(); + } + + private: + ~ThreadSafeProxy() override = default; + + const scoped_refptr<base::SequencedTaskRunner> task_runner_; + const Forwarder forwarder_; + mojo::AssociatedGroupController& group_controller_; +}; + +} // namespace + MessagePipeReader::MessagePipeReader( mojo::MessagePipeHandle pipe, - mojo::AssociatedRemote<mojom::Channel> sender, + mojo::PendingAssociatedRemote<mojom::Channel> sender, mojo::PendingAssociatedReceiver<mojom::Channel> receiver, + scoped_refptr<base::SequencedTaskRunner> task_runner, MessagePipeReader::Delegate* delegate) : delegate_(delegate), - sender_(std::move(sender)), - receiver_(this, std::move(receiver)) { + sender_(std::move(sender), task_runner), + receiver_(this, std::move(receiver), task_runner) { + thread_safe_sender_ = + std::make_unique<mojo::ThreadSafeForwarder<mojom::Channel>>( + base::MakeRefCounted<ThreadSafeProxy>( + task_runner, + base::BindRepeating(&MessagePipeReader::ForwardMessage, + weak_ptr_factory_.GetWeakPtr()), + *sender_.internal_state()->associated_group()->GetController())); + + thread_checker_.DetachFromThread(); +} + +MessagePipeReader::~MessagePipeReader() { + DCHECK(thread_checker_.CalledOnValidThread()); + // The pipe should be closed before deletion. +} + +void MessagePipeReader::FinishInitializationOnIOThread( + base::ProcessId self_pid) { sender_.set_disconnect_handler( base::BindOnce(&MessagePipeReader::OnPipeError, base::Unretained(this), MOJO_RESULT_FAILED_PRECONDITION)); receiver_.set_disconnect_handler( base::BindOnce(&MessagePipeReader::OnPipeError, base::Unretained(this), MOJO_RESULT_FAILED_PRECONDITION)); -} -MessagePipeReader::~MessagePipeReader() { - DCHECK(thread_checker_.CalledOnValidThread()); - // The pipe should be closed before deletion. + sender_->SetPeerPid(self_pid); } void MessagePipeReader::Close() { @@ -128,5 +182,9 @@ delegate_->OnPipeError(); } +void MessagePipeReader::ForwardMessage(mojo::Message message) { + sender_.internal_state()->ForwardMessage(std::move(message)); +} + } // namespace internal } // namespace IPC
diff --git a/ipc/ipc_message_pipe_reader.h b/ipc/ipc_message_pipe_reader.h index b7f73d2..1894bf3 100644 --- a/ipc/ipc_message_pipe_reader.h +++ b/ipc/ipc_message_pipe_reader.h
@@ -14,6 +14,7 @@ #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/process/process_handle.h" #include "base/threading/thread_checker.h" #include "ipc/ipc.mojom.h" @@ -22,6 +23,7 @@ #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" +#include "mojo/public/cpp/bindings/shared_remote.h" #include "mojo/public/cpp/system/core.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -68,11 +70,14 @@ // // Note that MessagePipeReader doesn't delete |delegate|. MessagePipeReader(mojo::MessagePipeHandle pipe, - mojo::AssociatedRemote<mojom::Channel> sender, + mojo::PendingAssociatedRemote<mojom::Channel> sender, mojo::PendingAssociatedReceiver<mojom::Channel> receiver, + scoped_refptr<base::SequencedTaskRunner> task_runner, Delegate* delegate); ~MessagePipeReader() override; + void FinishInitializationOnIOThread(base::ProcessId self_pid); + // Close and destroy the MessagePipe. void Close(); @@ -88,6 +93,7 @@ mojo::ScopedInterfaceEndpointHandle handle); mojo::AssociatedRemote<mojom::Channel>& sender() { return sender_; } + mojom::Channel& thread_safe_sender() { return thread_safe_sender_->proxy(); } protected: void OnPipeClosed(); @@ -102,11 +108,16 @@ mojo::PendingAssociatedReceiver<mojom::GenericInterface> receiver) override; + void ForwardMessage(mojo::Message message); + // |delegate_| is null once the message pipe is closed. Delegate* delegate_; mojo::AssociatedRemote<mojom::Channel> sender_; + std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>> + thread_safe_sender_; mojo::AssociatedReceiver<mojom::Channel> receiver_; base::ThreadChecker thread_checker_; + base::WeakPtrFactory<MessagePipeReader> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(MessagePipeReader); };
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc index 4c848850..35d6112 100644 --- a/ipc/ipc_mojo_bootstrap.cc +++ b/ipc/ipc_mojo_bootstrap.cc
@@ -164,11 +164,8 @@ } void Bind(mojo::ScopedMessagePipeHandle handle) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(task_runner_->BelongsToCurrentThread()); - connector_ = std::make_unique<mojo::Connector>( - std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, task_runner_, + std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, "IPC Channel"); connector_->set_incoming_receiver(&dispatcher_); connector_->set_connection_error_handler( @@ -185,6 +182,8 @@ // operation would only introduce a redundant scheduling step for most // messages. connector_->set_force_immediate_dispatch(true); + + connector_->StartReceiving(task_runner_); } void Pause() { @@ -211,7 +210,7 @@ } void CreateChannelEndpoints( - mojo::AssociatedRemote<mojom::Channel>* sender, + mojo::PendingAssociatedRemote<mojom::Channel>* sender, mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) { mojo::InterfaceId sender_id, receiver_id; if (set_interface_id_namespace_bit_) { @@ -237,8 +236,8 @@ mojo::ScopedInterfaceEndpointHandle receiver_handle = CreateScopedInterfaceEndpointHandle(receiver_id); - sender->Bind(mojo::PendingAssociatedRemote<mojom::Channel>( - std::move(sender_handle), 0)); + *sender = mojo::PendingAssociatedRemote<mojom::Channel>( + std::move(sender_handle), 0); *receiver = mojo::PendingAssociatedReceiver<mojom::Channel>( std::move(receiver_handle)); } @@ -511,6 +510,11 @@ return client_; } + void CountDroppedMessage() { + controller_->lock_.AssertAcquired(); + ++num_dropped_messages_; + } + void AttachClient(mojo::InterfaceEndpointClient* client, scoped_refptr<base::SequencedTaskRunner> runner) { controller_->lock_.AssertAcquired(); @@ -520,6 +524,15 @@ task_runner_ = std::move(runner); client_ = client; + + CHECK_EQ(num_dropped_messages_, 0u) + << "A Channel-associated interface endpoint for " + << client->interface_name() << " received undeliverable messages " + << "prior to being bound. This means the endpoint was held in a " + << "pending state longer than allowed. Channel-associated interface " + << "endpoints must be bound ASAP once received; either immediately " + << "on the IO or main thread, or after a single task hop from the IO " + << "thread to main thread where applicable."; } void DetachClient() { @@ -673,6 +686,7 @@ std::unique_ptr<mojo::SequenceLocalSyncEventWatcher> sync_watcher_; base::queue<std::pair<uint32_t, MessageWrapper>> sync_messages_; uint32_t next_sync_message_id_ = 0; + size_t num_dropped_messages_ = 0; DISALLOW_COPY_AND_ASSIGN(Endpoint); }; @@ -933,8 +947,10 @@ return; mojo::InterfaceEndpointClient* client = endpoint->client(); - if (!client) + if (!client) { + endpoint->CountDroppedMessage(); return; + } // Using client->interface_name() is safe here because this is a static // string defined for each mojo interface. @@ -1104,7 +1120,7 @@ private: void Connect( - mojo::AssociatedRemote<mojom::Channel>* sender, + mojo::PendingAssociatedRemote<mojom::Channel>* sender, mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) override { controller_->Bind(std::move(handle_)); controller_->CreateChannelEndpoints(sender, receiver); @@ -1144,7 +1160,7 @@ const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner, const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker) { return std::make_unique<MojoBootstrapImpl>( - std::move(handle), new ChannelAssociatedGroupController( + std::move(handle), base::MakeRefCounted<ChannelAssociatedGroupController>( mode == Channel::MODE_SERVER, ipc_task_runner, proxy_task_runner, quota_checker)); }
diff --git a/ipc/ipc_mojo_bootstrap.h b/ipc/ipc_mojo_bootstrap.h index d231ab2c..8d9b5745 100644 --- a/ipc/ipc_mojo_bootstrap.h +++ b/ipc/ipc_mojo_bootstrap.h
@@ -48,7 +48,7 @@ // Start the handshake over the underlying message pipe. virtual void Connect( - mojo::AssociatedRemote<mojom::Channel>* sender, + mojo::PendingAssociatedRemote<mojom::Channel>* sender, mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) = 0; // Stop transmitting messages and start queueing them instead.
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc index eddcde20..ddf1604 100644 --- a/ipc/ipc_mojo_bootstrap_unittest.cc +++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -26,7 +26,9 @@ explicit Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap, int32_t sender_id) : bootstrap_(std::move(bootstrap)) { - bootstrap_->Connect(&sender_, &receiver_); + mojo::PendingAssociatedRemote<IPC::mojom::Channel> sender; + bootstrap_->Connect(&sender, &receiver_); + sender_.Bind(std::move(sender)); sender_->SetPeerPid(sender_id); }
diff --git a/media/audio/android/aaudio_output.cc b/media/audio/android/aaudio_output.cc index 9e9b53ab..6ea70c6 100644 --- a/media/audio/android/aaudio_output.cc +++ b/media/audio/android/aaudio_output.cc
@@ -4,7 +4,10 @@ #include "media/audio/android/aaudio_output.h" +#include "base/callback_helpers.h" #include "base/logging.h" +#include "base/thread_annotations.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "media/audio/android/aaudio_stubs.h" #include "media/audio/android/audio_manager_android.h" @@ -12,14 +15,47 @@ namespace media { +// Used to circumvent issues where the AAudio thread callbacks continue +// after AAudioStream_requestStop() completes. See crbug.com/1183255. +class LOCKABLE AAudioDestructionHelper { + public: + explicit AAudioDestructionHelper(AAudioOutputStream* stream) + : stream_(stream) {} + + AAudioOutputStream* GetAndLockStream() EXCLUSIVE_LOCK_FUNCTION() { + lock_.Acquire(); + return stream_; + } + + void UnlockStream() UNLOCK_FUNCTION() { lock_.Release(); } + + void OnStreamDestroyed() { + base::AutoLock al(lock_); + stream_ = nullptr; + } + + private: + base::Lock lock_; + AAudioOutputStream* stream_ GUARDED_BY(lock_) = nullptr; +}; + static aaudio_data_callback_result_t OnAudioDataRequestedCallback( AAudioStream* stream, void* user_data, void* audio_data, int32_t num_frames) { - AAudioOutputStream* output_stream = - reinterpret_cast<AAudioOutputStream*>(user_data); - return output_stream->OnAudioDataRequested(audio_data, num_frames); + AAudioDestructionHelper* destruction_helper = + reinterpret_cast<AAudioDestructionHelper*>(user_data); + + AAudioOutputStream* output_stream = destruction_helper->GetAndLockStream(); + + aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP; + if (output_stream) + result = output_stream->OnAudioDataRequested(audio_data, num_frames); + + destruction_helper->UnlockStream(); + + return result; } static void OnStreamErrorCallback(AAudioStream* stream, @@ -38,7 +74,8 @@ usage_(usage), performance_mode_(AAUDIO_PERFORMANCE_MODE_NONE), ns_per_frame_(base::Time::kNanosecondsPerSecond / - static_cast<double>(params.sample_rate())) { + static_cast<double>(params.sample_rate())), + destruction_helper_(std::make_unique<AAudioDestructionHelper>(this)) { DCHECK(manager); DCHECK(params.IsValid()); @@ -66,6 +103,21 @@ AAudioOutputStream::~AAudioOutputStream() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // In R and earlier, it is possible for callbacks to still be running even + // after calling AAudioStream_close(). The code below is a mitigation to work + // around this issue. See crbug.com/1183255. + + // |destruction_helper_->GetStreamAndLock()| will return nullptr after this. + destruction_helper_->OnStreamDestroyed(); + + // Keep |destruction_helper_| alive longer than |this|, so the |user_data| + // bound to the callback stays valid until the callbacks stop. + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + base::DoNothing::Once<std::unique_ptr<AAudioDestructionHelper>>(), + std::move(destruction_helper_)), + base::TimeDelta::FromSeconds(1)); } void AAudioOutputStream::Flush() {} @@ -90,7 +142,7 @@ // Callbacks AAudioStreamBuilder_setDataCallback(builder, OnAudioDataRequestedCallback, - this); + destruction_helper_.get()); AAudioStreamBuilder_setErrorCallback(builder, OnStreamErrorCallback, this); result = AAudioStreamBuilder_openStream(builder, &aaudio_stream_);
diff --git a/media/audio/android/aaudio_output.h b/media/audio/android/aaudio_output.h index 5c6b7b2..35343369 100644 --- a/media/audio/android/aaudio_output.h +++ b/media/audio/android/aaudio_output.h
@@ -15,6 +15,7 @@ namespace media { +class AAudioDestructionHelper; class AudioManagerAndroid; class AAudioOutputStream : public MuteableAudioOutputStream { @@ -60,6 +61,10 @@ AAudioStream* aaudio_stream_ = nullptr; + // Bound to the audio data callback. Outlives |this| in case the callbacks + // continue after |this| is destroyed. See crbug.com/1183255. + std::unique_ptr<AAudioDestructionHelper> destruction_helper_; + // Lock protects all members below which may be read concurrently from the // audio manager thread and the OS provided audio thread. base::Lock lock_; @@ -74,4 +79,4 @@ } // namespace media -#endif // MEDIA_AUDIO_ANDROID_AAUDIO_OUTPUT_H_ \ No newline at end of file +#endif // MEDIA_AUDIO_ANDROID_AAUDIO_OUTPUT_H_
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc index cfa68cdd..c3a47f85 100644 --- a/media/base/android/media_drm_bridge.cc +++ b/media/base/android/media_drm_bridge.cc
@@ -747,8 +747,10 @@ DVLOG(2) << __func__; std::string session_id; JavaByteArrayToString(env, j_session_id, &session_id); + // TODO(crbug.com/1208618): Support other closed reasons. task_runner_->PostTask( - FROM_HERE, base::BindOnce(session_closed_cb_, std::move(session_id))); + FROM_HERE, base::BindOnce(session_closed_cb_, std::move(session_id), + CdmSessionClosedReason::kClose)); } void MediaDrmBridge::OnSessionKeysChange(
diff --git a/media/base/cdm_session_tracker.cc b/media/base/cdm_session_tracker.cc index da6f7b3..edd35f6 100644 --- a/media/base/cdm_session_tracker.cc +++ b/media/base/cdm_session_tracker.cc
@@ -24,12 +24,13 @@ } void CdmSessionTracker::CloseRemainingSessions( - const SessionClosedCB& session_closed_cb) { + const SessionClosedCB& session_closed_cb, + CdmSessionClosedReason reason) { std::unordered_set<std::string> session_ids; session_ids.swap(session_ids_); for (const auto& session_id : session_ids) - session_closed_cb.Run(session_id); + session_closed_cb.Run(session_id, reason); } bool CdmSessionTracker::HasRemainingSessions() const {
diff --git a/media/base/cdm_session_tracker.h b/media/base/cdm_session_tracker.h index 2d90264..504b0e3 100644 --- a/media/base/cdm_session_tracker.h +++ b/media/base/cdm_session_tracker.h
@@ -21,15 +21,16 @@ CdmSessionTracker(); ~CdmSessionTracker(); - // Adds |session_id| to the list of sessions being tracked. + // Adds `session_id` to the list of sessions being tracked. void AddSession(const std::string& session_id); - // Removes |session_id| from the list of sessions being tracked. + // Removes `session_id` from the list of sessions being tracked. void RemoveSession(const std::string& session_id); - // Calls |session_closed_cb| on any remaining sessions in the list and then - // clear the list. - void CloseRemainingSessions(const SessionClosedCB& session_closed_cb); + // Calls `session_closed_cb` with `reason` on any remaining sessions in the + // list and then clear the list. + void CloseRemainingSessions(const SessionClosedCB& session_closed_cb, + CdmSessionClosedReason reason); // Returns whether there are any remaining sessions being tracked. bool HasRemainingSessions() const;
diff --git a/media/base/content_decryption_module.h b/media/base/content_decryption_module.h index 31e1c85..1b4720ec 100644 --- a/media/base/content_decryption_module.h +++ b/media/base/content_decryption_module.h
@@ -71,6 +71,17 @@ kMaxValue = kHdcpVersion2_3 }; +// Reasons for CDM session closed. +enum class CdmSessionClosedReason { + kUnknown, // Anything not listed below. + kClose, // Reaction to MediaKeySession close(). + kCdmUnavailable, // CDM is no longer usable, e.g. the CDM was disconnected or + // had fatal internal-error. + kHardwareContextReset, // As a result of hardware context reset. + kResourceEvicted, // The CDM resource was evicted, e.g. by newer sessions. + kMaxValue = kResourceEvicted +}; + // An interface that represents the Content Decryption Module (CDM) in the // Encrypted Media Extensions (EME) spec in Chromium. // See http://w3c.github.io/encrypted-media/#cdm @@ -191,12 +202,14 @@ CdmMessageType message_type, const std::vector<uint8_t>& message)>; -// Called when the session specified by |session_id| is closed. Note that the +// Called when the session specified by `session_id` is closed. Note that the // CDM may close a session at any point, such as in response to a CloseSession() // call, when the session is no longer needed, or when system resources are -// lost. See http://w3c.github.io/encrypted-media/#session-close +// lost, as specified by `reason`. +// See http://w3c.github.io/encrypted-media/#session-close using SessionClosedCB = - base::RepeatingCallback<void(const std::string& session_id)>; + base::RepeatingCallback<void(const std::string& session_id, + CdmSessionClosedReason reason)>; // Called when there has been a change in the keys in the session or their // status. See http://w3c.github.io/encrypted-media/#dom-evt-keystatuseschange
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc index 981c436..9ed57758 100644 --- a/media/base/mock_filters.cc +++ b/media/base/mock_filters.cc
@@ -258,8 +258,9 @@ session_message_cb_.Run(session_id, message_type, message); } -void MockCdm::CallSessionClosedCB(const std::string& session_id) { - session_closed_cb_.Run(session_id); +void MockCdm::CallSessionClosedCB(const std::string& session_id, + CdmSessionClosedReason reason) { + session_closed_cb_.Run(session_id, reason); } void MockCdm::CallSessionKeysChangeCB(const std::string& session_id,
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index e70cb8c6..3e67b8a 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -573,7 +573,9 @@ void(const std::string& session_id, CdmMessageType message_type, const std::vector<uint8_t>& message)); - MOCK_METHOD1(OnSessionClosed, void(const std::string& session_id)); + MOCK_METHOD2(OnSessionClosed, + void(const std::string& session_id, + CdmSessionClosedReason reason)); // Add OnSessionKeysChangeCalled() function so we can store |keys_info|. MOCK_METHOD2(OnSessionKeysChangeCalled, @@ -740,7 +742,8 @@ void CallSessionMessageCB(const std::string& session_id, CdmMessageType message_type, const std::vector<uint8_t>& message); - void CallSessionClosedCB(const std::string& session_id); + void CallSessionClosedCB(const std::string& session_id, + CdmSessionClosedReason reason); void CallSessionKeysChangeCB(const std::string& session_id, bool has_additional_usable_key, CdmKeysInfo keys_info);
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc index e378e62..dc425419 100644 --- a/media/blink/cdm_session_adapter.cc +++ b/media/blink/cdm_session_adapter.cc
@@ -245,12 +245,14 @@ } } -void CdmSessionAdapter::OnSessionClosed(const std::string& session_id) { +void CdmSessionAdapter::OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason /*reason*/) { WebContentDecryptionModuleSessionImpl* session = GetSession(session_id); DLOG_IF(WARNING, !session) << __func__ << " for unknown session " << session_id; if (session) { DVLOG(2) << __func__ << ": session_id = " << session_id; + // TODO(crbug.com/1208618): Plumb `reason` to blink. session->OnSessionClosed(); } }
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h index 3325504..c4d9438 100644 --- a/media/blink/cdm_session_adapter.h +++ b/media/blink/cdm_session_adapter.h
@@ -134,7 +134,8 @@ CdmKeysInfo keys_info); void OnSessionExpirationUpdate(const std::string& session_id, base::Time new_expiry_time); - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason); // Helper function of the callbacks. WebContentDecryptionModuleSessionImpl* GetSession(
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index 417552dc1..800be34b 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc
@@ -367,7 +367,7 @@ // 5.3. Queue a task to run the following steps: // 5.3.1. Run the Session Closed algorithm on the session. - session_closed_cb_.Run(session_id); + session_closed_cb_.Run(session_id, CdmSessionClosedReason::kClose); // 5.3.2. Resolve promise. promise->resolve(); }
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc index cc6e245..9abcd5f 100644 --- a/media/cdm/aes_decryptor_unittest.cc +++ b/media/cdm/aes_decryptor_unittest.cc
@@ -381,7 +381,8 @@ // Closes the session specified by |session_id|. void CloseSession(const std::string& session_id) { - EXPECT_CALL(cdm_client_, OnSessionClosed(session_id)); + EXPECT_CALL(cdm_client_, + OnSessionClosed(session_id, CdmSessionClosedReason::kClose)); cdm_->CloseSession(session_id, CreatePromise(RESOLVED)); }
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc index c0a849ae..c3ceb95 100644 --- a/media/cdm/cdm_adapter.cc +++ b/media/cdm/cdm_adapter.cc
@@ -816,7 +816,8 @@ std::string session_id_str(session_id, session_id_size); TRACE_EVENT1("media", "CdmAdapter::OnSessionClosed", "session_id", session_id_str); - session_closed_cb_.Run(session_id_str); + // Library CDMs typically only close sessions as a result of `CloseSession()`. + session_closed_cb_.Run(session_id_str, CdmSessionClosedReason::kClose); } void CdmAdapter::SendPlatformChallenge(const char* service_id,
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc index ae1a929..4bbaa85 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -888,7 +888,8 @@ keys_vector.data(), keys_vector.size()); } -void ClearKeyCdm::OnSessionClosed(const std::string& session_id) { +void ClearKeyCdm::OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason /*reason*/) { cdm_host_proxy_->OnSessionClosed(session_id.data(), session_id.length()); }
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h index 79e86d52..b48293f 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h
@@ -109,7 +109,8 @@ void OnSessionKeysChange(const std::string& session_id, bool has_additional_usable_key, CdmKeysInfo keys_info); - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason); void OnSessionExpirationUpdate(const std::string& session_id, base::Time new_expiry_time);
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc index cc71d26d..a6adbf0d 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.cc
@@ -352,9 +352,10 @@ } void ClearKeyPersistentSessionCdm::OnSessionClosed( - const std::string& session_id) { + const std::string& session_id, + CdmSessionClosedReason reason) { persistent_sessions_.erase(session_id); - session_closed_cb_.Run(session_id); + session_closed_cb_.Run(session_id, reason); } void ClearKeyPersistentSessionCdm::OnSessionMessage(
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.h b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.h index b2ef8ee..5063180 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.h +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_persistent_session_cdm.h
@@ -99,7 +99,8 @@ // When the session is closed, remove it from the list of open persistent // sessions if it was a persistent session. - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason); void OnSessionMessage(const std::string& session_id, CdmMessageType message_type,
diff --git a/media/cdm/win/media_foundation_cdm.cc b/media/cdm/win/media_foundation_cdm.cc index 629aa4b..ec92442 100644 --- a/media/cdm/win/media_foundation_cdm.cc +++ b/media/cdm/win/media_foundation_cdm.cc
@@ -402,36 +402,8 @@ std::unique_ptr<SimpleCdmPromise> promise) { DVLOG_FUNC(1); - if (!mf_cdm_) { - promise->reject(Exception::INVALID_STATE_ERROR, 0, "CDM Unavailable"); - return; - } - - // Validate that this is a reference to an open session. close() shouldn't - // be called if the session is already closed. However, the operation is - // asynchronous, so there is a window where close() was called a second time - // just before the closed event arrives. As a result it is possible that the - // session is already closed, so assume that the session is closed if it - // doesn't exist. https://github.com/w3c/encrypted-media/issues/365. - // - // close() is called from a MediaKeySession object, so it is unlikely that - // this method will be called with a previously unseen |session_id|. - auto* session = GetSession(session_id); - if (!session) { - promise->resolve(); - return; - } - - if (FAILED(session->Close())) { - sessions_.erase(session_id); - promise->reject(Exception::INVALID_STATE_ERROR, 0, "Close failed"); - return; - } - - // EME requires running session closed algorithm before resolving the promise. - sessions_.erase(session_id); - session_closed_cb_.Run(session_id); - promise->resolve(); + CloseSessionInternal(session_id, CdmSessionClosedReason::kClose, + std::move(promise)); } void MediaFoundationCdm::RemoveSession( @@ -519,6 +491,44 @@ return itr->second.get(); } +void MediaFoundationCdm::CloseSessionInternal( + const std::string& session_id, + CdmSessionClosedReason reason, + std::unique_ptr<SimpleCdmPromise> promise) { + DVLOG_FUNC(1); + + if (!mf_cdm_) { + promise->reject(Exception::INVALID_STATE_ERROR, 0, "CDM Unavailable"); + return; + } + + // Validate that this is a reference to an open session. close() shouldn't + // be called if the session is already closed. However, the operation is + // asynchronous, so there is a window where close() was called a second time + // just before the closed event arrives. As a result it is possible that the + // session is already closed, so assume that the session is closed if it + // doesn't exist. https://github.com/w3c/encrypted-media/issues/365. + // + // close() is called from a MediaKeySession object, so it is unlikely that + // this method will be called with a previously unseen |session_id|. + auto* session = GetSession(session_id); + if (!session) { + promise->resolve(); + return; + } + + if (FAILED(session->Close())) { + sessions_.erase(session_id); + promise->reject(Exception::INVALID_STATE_ERROR, 0, "Close failed"); + return; + } + + // EME requires running session closed algorithm before resolving the promise. + sessions_.erase(session_id); + session_closed_cb_.Run(session_id, reason); + promise->resolve(); +} + // When hardware context is reset, all sessions are in a bad state. Close all // the sessions and hopefully the player will create new sessions to resume. void MediaFoundationCdm::OnHardwareContextReset() { @@ -530,8 +540,11 @@ for (const auto& s : sessions_) session_ids.push_back(s.first); - for (const auto& session_id : session_ids) - CloseSession(session_id, std::make_unique<DoNothingCdmPromise<>>()); + for (const auto& session_id : session_ids) { + CloseSessionInternal(session_id, + CdmSessionClosedReason::kHardwareContextReset, + std::make_unique<DoNothingCdmPromise<>>()); + } cdm_proxy_.reset();
diff --git a/media/cdm/win/media_foundation_cdm.h b/media/cdm/win/media_foundation_cdm.h index b49d287..bf97ad75 100644 --- a/media/cdm/win/media_foundation_cdm.h +++ b/media/cdm/win/media_foundation_cdm.h
@@ -88,7 +88,11 @@ MediaFoundationCdmSession* GetSession(const std::string& session_id); - // Closes all outstanding sessions. + void CloseSessionInternal(const std::string& session_id, + CdmSessionClosedReason reason, + std::unique_ptr<SimpleCdmPromise> promise); + + // Called when hardware context reset happens. void OnHardwareContextReset(); // Callback to create `mf_cdm_`.
diff --git a/media/cdm/win/media_foundation_cdm_unittest.cc b/media/cdm/win/media_foundation_cdm_unittest.cc index 0c57dae..bb37379e 100644 --- a/media/cdm/win/media_foundation_cdm_unittest.cc +++ b/media/cdm/win/media_foundation_cdm_unittest.cc
@@ -379,7 +379,8 @@ CreateSessionAndGenerateRequest(); COM_EXPECT_CALL(mf_cdm_session_, Close()).WillOnce(Return(S_OK)); - EXPECT_CALL(cdm_client_, OnSessionClosed(kSessionId)); + EXPECT_CALL(cdm_client_, + OnSessionClosed(kSessionId, CdmSessionClosedReason::kClose)); cdm_->CloseSession(session_id_, std::make_unique<MockCdmPromise>(/*expect_success=*/true)); @@ -433,7 +434,9 @@ ASSERT_TRUE(mf_cdm_proxy_); COM_EXPECT_CALL(mf_cdm_session_, Close()).WillOnce(Return(S_OK)); - EXPECT_CALL(cdm_client_, OnSessionClosed(kSessionId)); + EXPECT_CALL(cdm_client_, + OnSessionClosed(kSessionId, + CdmSessionClosedReason::kHardwareContextReset)); mf_cdm_proxy_->OnHardwareContextReset(); // Create a new session and expect success. @@ -454,7 +457,9 @@ can_initialize_ = false; COM_EXPECT_CALL(mf_cdm_session_, Close()).WillOnce(Return(S_OK)); - EXPECT_CALL(cdm_client_, OnSessionClosed(kSessionId)); + EXPECT_CALL(cdm_client_, + OnSessionClosed(kSessionId, + CdmSessionClosedReason::kHardwareContextReset)); mf_cdm_proxy_->OnHardwareContextReset(); std::vector<uint8_t> init_data = StringToVector("init_data");
diff --git a/media/fuchsia/cdm/fuchsia_cdm.cc b/media/fuchsia/cdm/fuchsia_cdm.cc index a4692f43..61a8c3fd 100644 --- a/media/fuchsia/cdm/fuchsia_cdm.cc +++ b/media/fuchsia/cdm/fuchsia_cdm.cc
@@ -143,8 +143,10 @@ } ~CdmSession() { - if (!session_id_.empty()) - session_callbacks_->closed_cb.Run(session_id_); + if (!session_id_.empty()) { + session_callbacks_->closed_cb.Run( + session_id_, CdmSessionClosedReason::kCdmUnavailable); + } } fidl::InterfaceRequest<fuchsia::media::drm::LicenseSession> NewRequest() {
diff --git a/media/gpu/command_buffer_helper.cc b/media/gpu/command_buffer_helper.cc index 36c9aab..6d88256 100644 --- a/media/gpu/command_buffer_helper.cc +++ b/media/gpu/command_buffer_helper.cc
@@ -49,7 +49,8 @@ #else gpu::SchedulingPriority::kNormal #endif // defined(OS_MAC) - ); + , + stub_->channel()->task_runner()); decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context()); }
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc index af3230f..88702de 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -517,11 +517,11 @@ // called already). for (const auto& it : picture_info_map_) { PictureInfo* picture_info = it.second.get(); - if (picture_info->gl_image) { + for (const auto& gl_image : picture_info->gl_images) { std::string dump_name = base::StringPrintf("media/vt_video_decode_accelerator_%d/picture_%d", memory_dump_id_, picture_info->bitstream_id); - picture_info->gl_image->OnMemoryDump(pmd, 0, dump_name); + gl_image->OnMemoryDump(pmd, 0, dump_name); } } @@ -1285,13 +1285,13 @@ // Drop references to allow the underlying buffer to be released. PictureInfo* picture_info = it->second.get(); if (picture_info->uses_shared_images) { - picture_info->scoped_shared_image = nullptr; + picture_info->scoped_shared_images.clear(); } else { gl_client_.bind_image.Run(picture_info->client_texture_id, gpu::GetPlatformSpecificTextureTarget(), nullptr, false); } - picture_info->gl_image = nullptr; + picture_info->gl_images.clear(); picture_info->bitstream_id = 0; // Mark the picture as available and try to complete pending output work. @@ -1461,38 +1461,38 @@ // If the next pending flush is for a reset, then the frame will be dropped. bool resetting = !pending_flush_tasks_.empty() && pending_flush_tasks_.front() == TASK_RESET; + if (resetting) + return true; - if (!resetting) { - DCHECK(frame.image.get()); - // If the |image_size| has changed, request new picture buffers and then - // wait for them. - // - // TODO(sandersd): When used by GpuVideoDecoder, we don't need to bother - // with this. We can tell that is the case when we also have a timestamp. - if (picture_size_ != frame.image_size) { - // Dismiss current pictures. - for (int32_t picture_id : assigned_picture_ids_) { - DVLOG(3) << "DismissPictureBuffer(" << picture_id << ")"; - client_->DismissPictureBuffer(picture_id); - } - assigned_picture_ids_.clear(); - picture_info_map_.clear(); - available_picture_ids_.clear(); - - // Request new pictures. - picture_size_ = frame.image_size; - DVLOG(3) << "ProvidePictureBuffers(" << kNumPictureBuffers - << frame.image_size.ToString() << ")"; - client_->ProvidePictureBuffers(kNumPictureBuffers, PIXEL_FORMAT_UNKNOWN, - 1, frame.image_size, - gpu::GetPlatformSpecificTextureTarget()); - return false; + DCHECK(frame.image.get()); + // If the |image_size| has changed, request new picture buffers and then + // wait for them. + // + // TODO(sandersd): When used by GpuVideoDecoder, we don't need to bother + // with this. We can tell that is the case when we also have a timestamp. + if (picture_size_ != frame.image_size) { + // Dismiss current pictures. + for (int32_t picture_id : assigned_picture_ids_) { + DVLOG(3) << "DismissPictureBuffer(" << picture_id << ")"; + client_->DismissPictureBuffer(picture_id); } - if (!SendFrame(frame)) - return false; - } + assigned_picture_ids_.clear(); + picture_info_map_.clear(); + available_picture_ids_.clear(); - return true; + // Request new pictures. + picture_size_ = frame.image_size; + // TODO(https://crbug.com/1210994): Remove XRGB support, and expose only + // PIXEL_FORMAT_NV12 and PIXEL_FORMAT_YUV420P10. + picture_format_ = PIXEL_FORMAT_XRGB; + DVLOG(3) << "ProvidePictureBuffers(" << kNumPictureBuffers + << frame.image_size.ToString() << ")"; + client_->ProvidePictureBuffers(kNumPictureBuffers, picture_format_, 1, + frame.image_size, + gpu::GetPlatformSpecificTextureTarget()); + return false; + } + return SendFrame(frame); } bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) { @@ -1508,100 +1508,124 @@ auto it = picture_info_map_.find(picture_id); DCHECK(it != picture_info_map_.end()); PictureInfo* picture_info = it->second.get(); - DCHECK(!picture_info->gl_image); + DCHECK(picture_info->gl_images.empty()); const gfx::BufferFormat buffer_format = config_.profile == VP9PROFILE_PROFILE2 ? gfx::BufferFormat::P010 : gfx::BufferFormat::YUV_420_BIPLANAR; - // TODO(https://crbug.com/1108909): BGRA is not an appropriate value for - // these parameters. - const GLenum gl_format = GL_BGRA_EXT; - const viz::ResourceFormat viz_resource_format = - viz::ResourceFormat::BGRA_8888; - - scoped_refptr<gl::GLImageIOSurface> gl_image( - gl::GLImageIOSurface::Create(frame.image_size, gl_format)); - if (!gl_image->InitializeWithCVPixelBuffer( - frame.image.get(), - gfx::GenericSharedMemoryId(g_cv_pixel_buffer_ids.GetNext()), - buffer_format)) { - NOTIFY_STATUS("Failed to initialize GLImageIOSurface", PLATFORM_FAILURE, - SFT_PLATFORM_ERROR); - } - gl_image->DisableInUseByWindowServer(); - gfx::ColorSpace color_space = GetImageBufferColorSpace(frame.image); - gl_image->SetColorSpaceForYUVToRGBConversion(color_space); - gl_image->SetColorSpaceShallow(color_space); - scoped_refptr<Picture::ScopedSharedImage> scoped_shared_image; - if (picture_info->uses_shared_images) { - gpu::SharedImageStub* shared_image_stub = client_->GetSharedImageStub(); - DCHECK(shared_image_stub); - const uint32_t shared_image_usage = - gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT; - gpu::Mailbox mailbox = gpu::Mailbox::GenerateForSharedImage(); - - gpu::SharedImageBackingGLCommon::InitializeGLTextureParams gl_params; - // ANGLE-on-Metal exposes IOSurfaces via GL_TEXTURE_2D. Be robust to that. - gl_params.target = gl_client_.supports_arb_texture_rectangle - ? GL_TEXTURE_RECTANGLE_ARB - : GL_TEXTURE_2D; - gl_params.internal_format = gl_format; - gl_params.format = gl_format; - gl_params.type = GL_UNSIGNED_BYTE; - gl_params.is_cleared = true; - gpu::SharedImageBackingGLCommon::UnpackStateAttribs gl_attribs; - - // A GL texture id is needed to create the legacy mailbox, which requires - // that the GL context be made current. - const bool kCreateLegacyMailbox = true; - if (!gl_client_.make_context_current.Run()) { - DLOG(ERROR) << "Failed to make context current"; - NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); - return false; - } - - auto shared_image = std::make_unique<gpu::SharedImageBackingGLImage>( - gl_image, mailbox, viz_resource_format, frame.image_size, color_space, - kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType, shared_image_usage, - gl_params, gl_attribs, gl_client_.is_passthrough); - - const bool success = shared_image_stub->factory()->RegisterBacking( - std::move(shared_image), kCreateLegacyMailbox); - if (!success) { - DLOG(ERROR) << "Failed to register shared image"; - NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); - return false; - } - - // Wrap the destroy callback in a lambda that ensures that it be called on - // the appropriate thread. - auto destroy_shared_image_lambda = - [](gpu::SharedImageStub::SharedImageDestructionCallback callback, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - task_runner->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), gpu::SyncToken())); - }; - auto destroy_shared_image_callback = base::BindOnce( - destroy_shared_image_lambda, - shared_image_stub->GetSharedImageDestructionCallback(mailbox), - gpu_task_runner_); - scoped_shared_image = scoped_refptr<Picture::ScopedSharedImage>( - new Picture::ScopedSharedImage( - mailbox, gl_params.target, - std::move(destroy_shared_image_callback))); - } else { - if (!gl_client_.bind_image.Run(picture_info->client_texture_id, - gpu::GetPlatformSpecificTextureTarget(), - gl_image, false)) { - DLOG(ERROR) << "Failed to bind image"; - NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); - return false; - } + std::vector<gfx::BufferPlane> planes; + switch (picture_format_) { + case PIXEL_FORMAT_NV12: + case PIXEL_FORMAT_YUV420P10: + planes.push_back(gfx::BufferPlane::Y); + planes.push_back(gfx::BufferPlane::UV); + break; + case PIXEL_FORMAT_XRGB: + planes.push_back(gfx::BufferPlane::DEFAULT); + break; + default: + NOTREACHED(); + break; } - picture_info->gl_image = gl_image; + + for (size_t plane = 0; plane < planes.size(); ++plane) { + const gfx::Size plane_size( + CVPixelBufferGetWidthOfPlane(frame.image.get(), plane), + CVPixelBufferGetHeightOfPlane(frame.image.get(), plane)); + gfx::BufferFormat plane_buffer_format = + gpu::GetPlaneBufferFormat(planes[plane], buffer_format); + // TODO(https://crbug.com/1108909): BGRA is not an appropriate value for + // these parameters. + const viz::ResourceFormat viz_resource_format = + (picture_format_ == PIXEL_FORMAT_XRGB) + ? viz::ResourceFormat::BGRA_8888 + : viz::GetResourceFormat(plane_buffer_format); + const GLenum gl_format = viz::GLDataFormat(viz_resource_format); + + scoped_refptr<gl::GLImageIOSurface> gl_image( + gl::GLImageIOSurface::Create(plane_size, gl_format)); + if (!gl_image->InitializeWithCVPixelBuffer( + frame.image.get(), plane, + gfx::GenericSharedMemoryId(g_cv_pixel_buffer_ids.GetNext()), + plane_buffer_format)) { + NOTIFY_STATUS("Failed to initialize GLImageIOSurface", PLATFORM_FAILURE, + SFT_PLATFORM_ERROR); + } + gl_image->DisableInUseByWindowServer(); + gl_image->SetColorSpaceForYUVToRGBConversion(color_space); + gl_image->SetColorSpaceShallow(color_space); + + if (picture_info->uses_shared_images) { + gpu::SharedImageStub* shared_image_stub = client_->GetSharedImageStub(); + DCHECK(shared_image_stub); + const uint32_t shared_image_usage = + gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT; + gpu::Mailbox mailbox = gpu::Mailbox::GenerateForSharedImage(); + + gpu::SharedImageBackingGLCommon::InitializeGLTextureParams gl_params; + // ANGLE-on-Metal exposes IOSurfaces via GL_TEXTURE_2D. Be robust to that. + gl_params.target = gl_client_.supports_arb_texture_rectangle + ? GL_TEXTURE_RECTANGLE_ARB + : GL_TEXTURE_2D; + gl_params.internal_format = gl_format; + gl_params.format = gl_format; + gl_params.type = GL_UNSIGNED_BYTE; + gl_params.is_cleared = true; + gpu::SharedImageBackingGLCommon::UnpackStateAttribs gl_attribs; + + // A GL texture id is needed to create the legacy mailbox, which requires + // that the GL context be made current. + const bool kCreateLegacyMailbox = true; + if (!gl_client_.make_context_current.Run()) { + DLOG(ERROR) << "Failed to make context current"; + NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); + return false; + } + + auto shared_image = std::make_unique<gpu::SharedImageBackingGLImage>( + gl_image, mailbox, viz_resource_format, plane_size, color_space, + kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType, shared_image_usage, + gl_params, gl_attribs, gl_client_.is_passthrough); + + const bool success = shared_image_stub->factory()->RegisterBacking( + std::move(shared_image), kCreateLegacyMailbox); + if (!success) { + DLOG(ERROR) << "Failed to register shared image"; + NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); + return false; + } + + // Wrap the destroy callback in a lambda that ensures that it be called on + // the appropriate thread. + auto destroy_shared_image_lambda = + [](gpu::SharedImageStub::SharedImageDestructionCallback callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), + gpu::SyncToken())); + }; + auto destroy_shared_image_callback = base::BindOnce( + destroy_shared_image_lambda, + shared_image_stub->GetSharedImageDestructionCallback(mailbox), + gpu_task_runner_); + picture_info->scoped_shared_images.push_back( + scoped_refptr<Picture::ScopedSharedImage>( + new Picture::ScopedSharedImage( + mailbox, gl_params.target, + std::move(destroy_shared_image_callback)))); + } else { + if (!gl_client_.bind_image.Run(picture_info->client_texture_id, + gpu::GetPlatformSpecificTextureTarget(), + gl_image, false)) { + DLOG(ERROR) << "Failed to bind image"; + NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); + return false; + } + } + picture_info->gl_images.push_back(gl_image); + } picture_info->bitstream_id = frame.bitstream_id; available_picture_ids_.pop_back(); @@ -1621,7 +1645,10 @@ // we don't need to use them when the image is never bound? Bindings are // typically only created when WebGL is in use. picture.set_read_lock_fences_enabled(true); - picture.set_scoped_shared_image(scoped_shared_image); + for (size_t plane = 0; plane < planes.size(); ++plane) { + picture.set_scoped_shared_image(picture_info->scoped_shared_images[plane], + plane); + } client_->PictureReady(std::move(picture)); return true; }
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.h b/media/gpu/mac/vt_video_decode_accelerator_mac.h index c7dc49bb..3afcdab 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.h +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.h
@@ -144,12 +144,12 @@ PictureInfo(uint32_t client_texture_id, uint32_t service_texture_id); ~PictureInfo(); - // If true, then |scoped_shared_image| is used and |client_texture_id| and + // If true, then |scoped_shared_images| is used and |client_texture_id| and // |service_texture_id| are not used. const bool uses_shared_images; // Information about the currently bound image, for OnMemoryDump(). - scoped_refptr<gl::GLImageIOSurface> gl_image; + std::vector<scoped_refptr<gl::GLImageIOSurface>> gl_images; int32_t bitstream_id = 0; // Texture IDs for the image buffer. @@ -157,7 +157,7 @@ const uint32_t service_texture_id = 0; // The shared image holder that will be passed to the client. - scoped_refptr<Picture::ScopedSharedImage> scoped_shared_image; + std::vector<scoped_refptr<Picture::ScopedSharedImage>> scoped_shared_images; private: DISALLOW_COPY_AND_ASSIGN(PictureInfo); @@ -246,6 +246,9 @@ // Size of assigned picture buffers. gfx::Size picture_size_; + // Format of the assigned picture buffers. + VideoPixelFormat picture_format_ = PIXEL_FORMAT_UNKNOWN; + // Frames that have not yet been decoded, keyed by bitstream ID; maintains // ownership of Frame objects while they flow through VideoToolbox. std::map<int32_t, std::unique_ptr<Frame>> pending_frames_;
diff --git a/media/gpu/mac/vt_video_encode_accelerator_mac.cc b/media/gpu/mac/vt_video_encode_accelerator_mac.cc index a7e1c74..a59cadf3 100644 --- a/media/gpu/mac/vt_video_encode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_encode_accelerator_mac.cc
@@ -163,7 +163,10 @@ client_ptr_factory_ = std::make_unique<base::WeakPtrFactory<Client>>(client); client_ = client_ptr_factory_->GetWeakPtr(); input_visible_size_ = config.input_visible_size; - frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; + if (config.initial_framerate.has_value()) + frame_rate_ = config.initial_framerate.value(); + else + frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; initial_bitrate_ = config.initial_bitrate; bitstream_buffer_size_ = config.input_visible_size.GetArea(); require_low_delay_ = config.require_low_delay; @@ -339,13 +342,11 @@ return; } - if (framerate != static_cast<uint32_t>(frame_rate_)) { - video_toolbox::SessionPropertySetter session_property_setter( - compression_session_); - session_property_setter.Set(kVTCompressionPropertyKey_ExpectedFrameRate, - frame_rate_); - } - + frame_rate_ = framerate; + video_toolbox::SessionPropertySetter session_property_setter( + compression_session_); + session_property_setter.Set(kVTCompressionPropertyKey_ExpectedFrameRate, + frame_rate_); if (bitrate != static_cast<uint32_t>(target_bitrate_) && bitrate > 0) { target_bitrate_ = bitrate; bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_);
diff --git a/media/mojo/clients/mojo_cdm.cc b/media/mojo/clients/mojo_cdm.cc index 3a7e883e..ad33cb1a 100644 --- a/media/mojo/clients/mojo_cdm.cc +++ b/media/mojo/clients/mojo_cdm.cc
@@ -87,7 +87,8 @@ // Reject any outstanding promises and close all the existing sessions. cdm_promise_adapter_.Clear(CdmPromiseAdapter::ClearReason::kDestruction); - cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_); + cdm_session_tracker_.CloseRemainingSessions( + session_closed_cb_, CdmSessionClosedReason::kCdmUnavailable); } // Using base::Unretained(this) below is safe because |this| owns |remote_cdm_|, @@ -107,7 +108,8 @@ // As communication with the remote CDM is broken, reject any outstanding // promises and close all the existing sessions. cdm_promise_adapter_.Clear(CdmPromiseAdapter::ClearReason::kConnectionError); - cdm_session_tracker_.CloseRemainingSessions(session_closed_cb_); + cdm_session_tracker_.CloseRemainingSessions( + session_closed_cb_, CdmSessionClosedReason::kCdmUnavailable); } void MojoCdm::SetServerCertificate(const std::vector<uint8_t>& certificate, @@ -293,12 +295,13 @@ session_message_cb_.Run(session_id, message_type, message); } -void MojoCdm::OnSessionClosed(const std::string& session_id) { +void MojoCdm::OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason) { DVLOG(2) << __func__; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); cdm_session_tracker_.RemoveSession(session_id); - session_closed_cb_.Run(session_id); + session_closed_cb_.Run(session_id, reason); } void MojoCdm::OnSessionKeysChange(
diff --git a/media/mojo/clients/mojo_cdm.h b/media/mojo/clients/mojo_cdm.h index ee3ae28..4417e04 100644 --- a/media/mojo/clients/mojo_cdm.h +++ b/media/mojo/clients/mojo_cdm.h
@@ -94,7 +94,8 @@ void OnSessionMessage(const std::string& session_id, MessageType message_type, const std::vector<uint8_t>& message) final; - void OnSessionClosed(const std::string& session_id) final; + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason) final; void OnSessionKeysChange( const std::string& session_id, bool has_additional_usable_key,
diff --git a/media/mojo/clients/mojo_cdm_unittest.cc b/media/mojo/clients/mojo_cdm_unittest.cc index bf9a0d8f..5475007 100644 --- a/media/mojo/clients/mojo_cdm_unittest.cc +++ b/media/mojo/clients/mojo_cdm_unittest.cc
@@ -215,8 +215,11 @@ // MojoCdm expects the session to be closed, so invoke SessionClosedCB // to "close" it. - EXPECT_CALL(cdm_client_, OnSessionClosed(session_id)); - remote_cdm_->CallSessionClosedCB(session_id); + EXPECT_CALL( + cdm_client_, + OnSessionClosed(session_id, CdmSessionClosedReason::kUnknown)); + remote_cdm_->CallSessionClosedCB(session_id, + CdmSessionClosedReason::kUnknown); base::RunLoop().RunUntilIdle(); } } @@ -426,7 +429,9 @@ CreateSessionAndExpect(session_id, SUCCESS); // Created session should always be closed! - EXPECT_CALL(cdm_client_, OnSessionClosed(session_id)); + EXPECT_CALL( + cdm_client_, + OnSessionClosed(session_id, CdmSessionClosedReason::kCdmUnavailable)); } TEST_F(MojoCdmTest, CreateSession_Failure) {
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn index 78d210c..7e3d085 100644 --- a/media/mojo/mojom/BUILD.gn +++ b/media/mojo/mojom/BUILD.gn
@@ -552,6 +552,15 @@ { types = [ { + mojom = "media.mojom.CdmSessionClosedReason" + cpp = "::media::CdmSessionClosedReason" + }, + ] + traits_headers = [ "media_types_enum_mojom_traits.h" ] + }, + { + types = [ + { mojom = "media.mojom.RendererType" cpp = "::media::RendererType" }, @@ -560,6 +569,36 @@ }, ] + if (!is_android) { + cpp_typemaps += [ + { + types = [ + { + mojom = "media.mojom.HypothesisParts" + cpp = "::media::HypothesisParts" + }, + { + mojom = "media.mojom.TimingInformation" + cpp = "::media::TimingInformation" + }, + { + mojom = "media.mojom.SpeechRecognitionResult" + cpp = "::media::SpeechRecognitionResult" + }, + ] + traits_headers = [ + "speech_recognition_result_mojom_traits.h", + "speech_recognition_result.h", + ] + traits_sources = [ + "speech_recognition_result.cc", + "speech_recognition_result_mojom_traits.cc", + ] + traits_public_deps = [ "//base" ] + }, + ] + } + cpp_typemaps += shared_typemaps blink_cpp_typemaps = shared_typemaps @@ -615,6 +654,10 @@ "video_frame_mojom_traits_unittest.cc", ] + if (!is_android) { + sources += [ "speech_recognition_result_mojom_traits_unittest.cc" ] + } + deps = [ "//base", "//base/test:test_support",
diff --git a/media/mojo/mojom/content_decryption_module.mojom b/media/mojo/mojom/content_decryption_module.mojom index c0e8e251..eda8b0b86 100644 --- a/media/mojo/mojom/content_decryption_module.mojom +++ b/media/mojo/mojom/content_decryption_module.mojom
@@ -5,6 +5,7 @@ module media.mojom; import "media/mojo/mojom/decryptor.mojom"; +import "media/mojo/mojom/media_types.mojom"; import "url/mojom/url.mojom"; import "mojo/public/mojom/base/unguessable_token.mojom"; @@ -65,12 +66,18 @@ }; // An interface that represents a CDM in the Encrypted Media Extensions (EME) -// spec (https://w3c.github.io/encrypted-media/). For security reason, the CDM -// is running in its own CDM process as the CDM contains untrusted code and -// handles arbitrary data. -// See media/base/content_decryption_module.h +// spec (https://w3c.github.io/encrypted-media/). +// - Process Model: For security reason, the CDM is running in its own process +// as the CDM contains untrusted code and handles arbitrary data. The exact +// process model varies on various platforms. For example, on desktop, the CDM +// runs in a CDM (utility) process. On Android, the CDM runs in the GPU process. +// The client of the CDM is MojoCdm, which runs in the render process. +// - Session ID: Passed as `session_id` in some methods, it is a unique string +// identifier generated by the CDM that can be used to identify CDM sessions. +// A ContentDecryptionModule can manage mutilple sessions per the EME spec. See +// https://www.w3.org/TR/encrypted-media/#session-id. +// - Also see media/base/content_decryption_module.h and media/mojo/README.md. interface ContentDecryptionModule { - // Sets ContentDecryptionModuleClient. Must be called before any other calls. // Use associated interface to ensure ordering, e.g. events on the client // interface and promise fulfillment. @@ -117,17 +124,32 @@ RemoveSession(string session_id) => (CdmPromiseResult result); }; -// Session callbacks. See media/base/content_decryption_module.h for details. +// Session callbacks. The implementation is MojoCdm that runs in the render +// process. The caller is the remote CDM (mojom::ContentDecryptionModule). See +// comments above for more details on CDM process model and session ID. +// Also see media/base/content_decryption_module.h and media/mojo/README.md. interface ContentDecryptionModuleClient { + // Called when the CDM needs to queue a message event to the session object. + // See http://w3c.github.io/encrypted-media/#dom-evt-message OnSessionMessage(string session_id, CdmMessageType message_type, array<uint8> message); - OnSessionClosed(string session_id); + // Called when the session specified by |session_id| is closed. Note that the + // CDM may close a session at any point, e.g. in response to `CloseSession()`, + // when the session is no longer needed, or when system resources are lost. + // After `OnSessionClosed()` is called for a `session_id`, no methods in this + // interface should be called with the same `session_id`. + // See http://w3c.github.io/encrypted-media/#session-close + OnSessionClosed(string session_id, CdmSessionClosedReason reason); + // Called when there has been a change in the keys in the session or their + // status. + // See http://w3c.github.io/encrypted-media/#dom-evt-keystatuseschange OnSessionKeysChange(string session_id, bool has_additional_usable_key, array<CdmKeyInformation> keys_info); - // Provide session expiration update for |session_id|. + // Called when the CDM changes the expiration time of a session. + // See http://w3c.github.io/encrypted-media/#update-expiration // |new_expiry_time_sec| is the number of seconds since epoch (Jan 1, 1970). OnSessionExpirationUpdate(string session_id, double new_expiry_time_sec); };
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom index bf134ce..a2946185 100644 --- a/media/mojo/mojom/media_types.mojom +++ b/media/mojo/mojom/media_types.mojom
@@ -151,7 +151,6 @@ RangeID range; }; - // This defines a mojo transport format for media::AudioDecoderConfig. // See media/base/audio_decoder_config.h for descriptions. struct AudioDecoderConfig { @@ -187,6 +186,14 @@ [Native] struct SubsampleEntry; +enum CdmSessionClosedReason { + kUnknown, + kClose, + kCdmUnavailable, + kHardwareContextReset, + kResourceEvicted, +}; + // This defines a mojo transport format for media::DecryptConfig. // See media/base/decrypt_config.h for descriptions. struct DecryptConfig {
diff --git a/media/mojo/mojom/media_types_enum_mojom_traits.h b/media/mojo/mojom/media_types_enum_mojom_traits.h index ec91fe6a..cf6e3ea 100644 --- a/media/mojo/mojom/media_types_enum_mojom_traits.h +++ b/media/mojo/mojom/media_types_enum_mojom_traits.h
@@ -18,6 +18,56 @@ namespace mojo { template <> +struct EnumTraits<media::mojom::CdmSessionClosedReason, + ::media::CdmSessionClosedReason> { + static media::mojom::CdmSessionClosedReason ToMojom( + ::media::CdmSessionClosedReason input) { + switch (input) { + case ::media::CdmSessionClosedReason::kUnknown: + return media::mojom::CdmSessionClosedReason::kUnknown; + case ::media::CdmSessionClosedReason::kClose: + return media::mojom::CdmSessionClosedReason::kClose; + case ::media::CdmSessionClosedReason::kCdmUnavailable: + return media::mojom::CdmSessionClosedReason::kCdmUnavailable; + case ::media::CdmSessionClosedReason::kHardwareContextReset: + return media::mojom::CdmSessionClosedReason::kHardwareContextReset; + case ::media::CdmSessionClosedReason::kResourceEvicted: + return media::mojom::CdmSessionClosedReason::kResourceEvicted; + } + + NOTREACHED(); + return static_cast<media::mojom::CdmSessionClosedReason>(input); + } + + // Returning false results in deserialization failure and causes the + // message pipe receiving it to be disconnected. + static bool FromMojom(media::mojom::CdmSessionClosedReason input, + ::media::CdmSessionClosedReason* output) { + switch (input) { + case media::mojom::CdmSessionClosedReason::kUnknown: + *output = ::media::CdmSessionClosedReason::kUnknown; + return true; + case media::mojom::CdmSessionClosedReason::kClose: + *output = ::media::CdmSessionClosedReason::kClose; + return true; + case media::mojom::CdmSessionClosedReason::kCdmUnavailable: + *output = ::media::CdmSessionClosedReason::kCdmUnavailable; + return true; + case media::mojom::CdmSessionClosedReason::kHardwareContextReset: + *output = ::media::CdmSessionClosedReason::kHardwareContextReset; + return true; + case media::mojom::CdmSessionClosedReason::kResourceEvicted: + *output = ::media::CdmSessionClosedReason::kResourceEvicted; + return true; + } + + NOTREACHED(); + *output = static_cast<::media::CdmSessionClosedReason>(input); + return false; + } +}; + +template <> struct EnumTraits<media::mojom::VideoRotation, ::media::VideoRotation> { static media::mojom::VideoRotation ToMojom(::media::VideoRotation input) { switch (input) {
diff --git a/media/mojo/mojom/speech_recognition_result.cc b/media/mojo/mojom/speech_recognition_result.cc new file mode 100644 index 0000000..eb99456 --- /dev/null +++ b/media/mojo/mojom/speech_recognition_result.cc
@@ -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. + +#include "media/mojo/mojom/speech_recognition_result.h" + +namespace media { + +HypothesisParts::HypothesisParts() = default; +HypothesisParts::HypothesisParts(const std::vector<std::string> part, + base::TimeDelta offset) + : text(part), hypothesis_part_offset(offset) {} + +HypothesisParts::HypothesisParts(const HypothesisParts&) = default; +HypothesisParts::HypothesisParts(HypothesisParts&&) = default; +HypothesisParts& HypothesisParts::operator=(const HypothesisParts&) = default; +HypothesisParts& HypothesisParts::operator=(HypothesisParts&&) = default; +HypothesisParts::~HypothesisParts() = default; + +bool HypothesisParts::operator==(const HypothesisParts& rhs) const { + return text == rhs.text && + hypothesis_part_offset == rhs.hypothesis_part_offset; +} + +TimingInformation::TimingInformation() = default; +TimingInformation::TimingInformation(const TimingInformation&) = default; +TimingInformation::TimingInformation(TimingInformation&&) = default; +TimingInformation& TimingInformation::operator=(const TimingInformation&) = + default; +TimingInformation& TimingInformation::operator=(TimingInformation&&) = default; +TimingInformation::~TimingInformation() = default; + +bool TimingInformation::operator==(const TimingInformation& rhs) const { + return audio_start_time == rhs.audio_start_time && + audio_end_time == rhs.audio_end_time && + hypothesis_parts == rhs.hypothesis_parts; +} + +SpeechRecognitionResult::SpeechRecognitionResult() = default; +SpeechRecognitionResult::SpeechRecognitionResult(const std::string transcript, + bool is_final) + : transcription(transcript), is_final(is_final) {} + +SpeechRecognitionResult::SpeechRecognitionResult( + const SpeechRecognitionResult&) = default; +SpeechRecognitionResult::SpeechRecognitionResult(SpeechRecognitionResult&&) = + default; +SpeechRecognitionResult& SpeechRecognitionResult::operator=( + const SpeechRecognitionResult&) = default; +SpeechRecognitionResult& SpeechRecognitionResult::operator=( + SpeechRecognitionResult&&) = default; +SpeechRecognitionResult::~SpeechRecognitionResult() = default; + +bool SpeechRecognitionResult::operator==( + const SpeechRecognitionResult& rhs) const { + return transcription == rhs.transcription && is_final == rhs.is_final && + timing_information == rhs.timing_information; +} + +} // namespace media
diff --git a/media/mojo/mojom/speech_recognition_result.h b/media/mojo/mojom/speech_recognition_result.h new file mode 100644 index 0000000..269388b5 --- /dev/null +++ b/media/mojo/mojom/speech_recognition_result.h
@@ -0,0 +1,91 @@ +// 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_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_H_ +#define MEDIA_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_H_ + +#include <string> +#include <vector> + +#include "base/time/time.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { + +struct HypothesisParts { + HypothesisParts(); + HypothesisParts(const std::vector<std::string> part, base::TimeDelta offset); + HypothesisParts(const HypothesisParts&); + HypothesisParts(HypothesisParts&&); + HypothesisParts& operator=(const HypothesisParts&); + HypothesisParts& operator=(HypothesisParts&&); + ~HypothesisParts(); + + bool operator==(const HypothesisParts& rhs) const; + + // A section of the final transcription text. Either an entire word or single + // character (depending on the language) with adjacent punctuation. There will + // usually only be one value here. If formatting is enabled in the speech + // recognition, then the raw text will be included as the second element. + std::vector<std::string> text; + + // Time offset from this event's |audio_start_time| defined below. Time + // offset from this event's |audio_start_time| defined below. We enforce the + // following invariant: 0 <= hypothesis_part_offset < |audio_end_time - + // audio_start_time|. + base::TimeDelta hypothesis_part_offset; +}; + +struct TimingInformation { + TimingInformation(); + TimingInformation(const TimingInformation&); + TimingInformation(TimingInformation&&); + TimingInformation& operator=(const TimingInformation&); + TimingInformation& operator=(TimingInformation&&); + ~TimingInformation(); + + bool operator==(const TimingInformation& rhs) const; + + // Start time in audio time from the start of the SODA session. + // This time measures the amount of audio input into SODA. + base::TimeDelta audio_start_time; + + // Elapsed processed audio from first frame after preamble. + base::TimeDelta audio_end_time; + + // The timing information for each word/letter in the transription. + // HypothesisPartsInResult was introduced in min version 1 in + // chromeos/services/machine_learning/public/mojom/soda.mojom. Therefore, it + // must be optional. Hypothesis parts maybe non-empty optional containing a + // zero length vector if no words were spoken during the event's time span. + absl::optional<std::vector<HypothesisParts>> hypothesis_parts; +}; + +// A speech recognition result created by the speech service and passed to the +// SpeechRecognitionRecognizerClient. +struct SpeechRecognitionResult { + SpeechRecognitionResult(); + SpeechRecognitionResult(const std::string transcript, bool is_final); + SpeechRecognitionResult(const SpeechRecognitionResult&); + SpeechRecognitionResult(SpeechRecognitionResult&&); + SpeechRecognitionResult& operator=(const SpeechRecognitionResult&); + SpeechRecognitionResult& operator=(SpeechRecognitionResult&&); + ~SpeechRecognitionResult(); + + bool operator==(const SpeechRecognitionResult& rhs) const; + + std::string transcription; + + // A flag indicating whether the result is final. If true, the result is + // locked in and the next result returned will not overlap with the previous + // final result. + bool is_final = false; + + // Timing information for the current transcription. + absl::optional<TimingInformation> timing_information; +}; + +} // namespace media + +#endif // MEDIA_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_H_
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits.cc b/media/mojo/mojom/speech_recognition_result_mojom_traits.cc new file mode 100644 index 0000000..e5205a39 --- /dev/null +++ b/media/mojo/mojom/speech_recognition_result_mojom_traits.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 "media/mojo/mojom/speech_recognition_result_mojom_traits.h" + +namespace mojo { + +namespace { + +constexpr base::TimeDelta kZeroTime = base::TimeDelta::FromSeconds(0); + +} // namespace + +// static +bool StructTraits< + media::mojom::HypothesisPartsDataView, + media::HypothesisParts>::Read(media::mojom::HypothesisPartsDataView data, + media::HypothesisParts* out) { + std::vector<std::string> text; + base::TimeDelta offset = kZeroTime; + + if (!data.ReadText(&text) || !data.ReadHypothesisPartOffset(&offset)) + return false; + if (offset < kZeroTime) + return false; + + out->text = std::move(text); + out->hypothesis_part_offset = offset; + return true; +} + +bool StructTraits<media::mojom::TimingInformationDataView, + media::TimingInformation>:: + Read(media::mojom::TimingInformationDataView data, + media::TimingInformation* out) { + base::TimeDelta audio_start_time = kZeroTime; + base::TimeDelta audio_end_time = kZeroTime; + absl::optional<std::vector<media::HypothesisParts>> hypothesis_parts; + + if (!data.ReadAudioStartTime(&audio_start_time) || + !data.ReadAudioEndTime(&audio_end_time) || + !data.ReadHypothesisParts(&hypothesis_parts)) { + return false; + } + + if (audio_start_time < kZeroTime || audio_end_time < audio_start_time) + return false; + + if (hypothesis_parts.has_value() && hypothesis_parts->size() > 0) { + base::TimeDelta prev_offset = kZeroTime; + base::TimeDelta max_offset = audio_end_time - audio_start_time; + for (const auto& part : *hypothesis_parts) { + if (part.hypothesis_part_offset < prev_offset || + part.hypothesis_part_offset >= max_offset) { + return false; + } + prev_offset = part.hypothesis_part_offset; + } + } + + out->audio_start_time = audio_start_time; + out->audio_end_time = audio_end_time; + out->hypothesis_parts = std::move(hypothesis_parts); + return true; +} + +bool StructTraits<media::mojom::SpeechRecognitionResultDataView, + media::SpeechRecognitionResult>:: + Read(media::mojom::SpeechRecognitionResultDataView data, + media::SpeechRecognitionResult* out) { + std::string transcription; + absl::optional<media::TimingInformation> timing_information; + + if (!data.ReadTranscription(&transcription) || + !data.ReadTimingInformation(&timing_information)) { + return false; + } + + // Timing information is provided only for final results. + if (!data.is_final() && timing_information.has_value()) + return false; + + out->transcription = std::move(transcription); + out->is_final = data.is_final(); + out->timing_information = std::move(timing_information); + return true; +} + +} // namespace mojo
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits.h b/media/mojo/mojom/speech_recognition_result_mojom_traits.h new file mode 100644 index 0000000..c3eb1509 --- /dev/null +++ b/media/mojo/mojom/speech_recognition_result_mojom_traits.h
@@ -0,0 +1,80 @@ +// 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_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_MOJOM_TRAITS_H_ +#define MEDIA_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_MOJOM_TRAITS_H_ + +#include <string> +#include <vector> + +#include "base/time/time.h" +#include "media/mojo/mojom/speech_recognition_result.h" +#include "media/mojo/mojom/speech_recognition_service.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace mojo { + +template <> +class StructTraits<media::mojom::HypothesisPartsDataView, + media::HypothesisParts> { + public: + static const std::vector<std::string>& text(const media::HypothesisParts& r) { + return r.text; + } + + static base::TimeDelta hypothesis_part_offset( + const media::HypothesisParts& r) { + return r.hypothesis_part_offset; + } + + static bool Read(media::mojom::HypothesisPartsDataView data, + media::HypothesisParts* out); +}; + +template <> +class StructTraits<media::mojom::TimingInformationDataView, + media::TimingInformation> { + public: + static base::TimeDelta audio_start_time(const media::TimingInformation& r) { + return r.audio_start_time; + } + + static base::TimeDelta audio_end_time(const media::TimingInformation& r) { + return r.audio_end_time; + } + + static const ::absl::optional<std::vector<media::HypothesisParts>>& + hypothesis_parts(const media::TimingInformation& r) { + return r.hypothesis_parts; + } + + static bool Read(media::mojom::TimingInformationDataView data, + media::TimingInformation* out); +}; + +template <> +class StructTraits<media::mojom::SpeechRecognitionResultDataView, + media::SpeechRecognitionResult> { + public: + static const std::string& transcription( + const media::SpeechRecognitionResult& r) { + return r.transcription; + } + + static bool is_final(const media::SpeechRecognitionResult& r) { + return r.is_final; + } + + static const ::absl::optional<media::TimingInformation>& timing_information( + const media::SpeechRecognitionResult& r) { + return r.timing_information; + } + + static bool Read(media::mojom::SpeechRecognitionResultDataView data, + media::SpeechRecognitionResult* out); +}; + +} // namespace mojo + +#endif // MEDIA_MOJO_MOJOM_SPEECH_RECOGNITION_RESULT_MOJOM_TRAITS_H_
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc b/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc new file mode 100644 index 0000000..42a83fb --- /dev/null +++ b/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc
@@ -0,0 +1,115 @@ +// 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/mojo/mojom/speech_recognition_result_mojom_traits.h" + +#include <vector> + +#include "base/time/time.h" +#include "media/mojo/mojom/speech_recognition_result.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace { + +base::TimeDelta kZeroTime = base::TimeDelta::FromSeconds(0); + +} + +TEST(SpeechRecognitionResultStructTraitsTest, NoTimingInformation) { + media::SpeechRecognitionResult result("hello world", true); + std::vector<uint8_t> data = + media::mojom::SpeechRecognitionResult::Serialize(&result); + media::SpeechRecognitionResult output; + EXPECT_TRUE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(data), &output)); + EXPECT_EQ(result, output); +} + +TEST(SpeechRecognitionResultStructTraitsTest, WithTimingInformation) { + media::SpeechRecognitionResult invalid_result("hello world", true); + invalid_result.timing_information = media::TimingInformation(); + invalid_result.timing_information->audio_start_time = kZeroTime; + invalid_result.timing_information->audio_end_time = + base::TimeDelta::FromSeconds(-1); + std::vector<uint8_t> data = + media::mojom::SpeechRecognitionResult::Serialize(&invalid_result); + media::SpeechRecognitionResult output; + EXPECT_FALSE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(data), &output)); + + media::SpeechRecognitionResult valid_result("hello world", true); + valid_result.timing_information = media::TimingInformation(); + valid_result.timing_information->audio_start_time = kZeroTime; + valid_result.timing_information->audio_end_time = + base::TimeDelta::FromSeconds(1); + std::vector<uint8_t> valid_data = + media::mojom::SpeechRecognitionResult::Serialize(&valid_result); + media::SpeechRecognitionResult valid_output; + EXPECT_TRUE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(valid_data), &valid_output)); + EXPECT_EQ(valid_result, valid_output); +} + +TEST(SpeechRecognitionResultStructTraitsTest, + PartialResultWithTimingInformation) { + media::SpeechRecognitionResult invalid_result("hello world", false); + invalid_result.timing_information = media::TimingInformation(); + invalid_result.timing_information->audio_start_time = kZeroTime; + invalid_result.timing_information->audio_end_time = + base::TimeDelta::FromSeconds(1); + std::vector<uint8_t> invalid_data = + media::mojom::SpeechRecognitionResult::Serialize(&invalid_result); + media::SpeechRecognitionResult invalid_output; + + // Partial results shouldn't have timing information. + EXPECT_FALSE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(invalid_data), &invalid_output)); +} + +TEST(SpeechRecognitionResultStructTraitsTest, WithInvalidHypothesisParts) { + media::SpeechRecognitionResult invalid_result("hello world", true); + invalid_result.timing_information = media::TimingInformation(); + invalid_result.timing_information->audio_start_time = kZeroTime; + invalid_result.timing_information->audio_end_time = + base::TimeDelta::FromSeconds(1); + invalid_result.timing_information->hypothesis_parts = + std::vector<media::HypothesisParts>(); + auto& hypothesis_parts = + invalid_result.timing_information->hypothesis_parts.value(); + hypothesis_parts.emplace_back(std::vector<std::string>({"hello"}), + base::TimeDelta::FromSeconds(-1)); + hypothesis_parts.emplace_back(std::vector<std::string>({"world"}), + base::TimeDelta::FromSeconds(1)); + std::vector<uint8_t> data = + media::mojom::SpeechRecognitionResult::Serialize(&invalid_result); + media::SpeechRecognitionResult output; + EXPECT_FALSE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(data), &output)); +} + +TEST(SpeechRecognitionResultStructTraitsTest, WithValidHypothesisParts) { + media::SpeechRecognitionResult valid_result("hello world", true); + valid_result.timing_information = media::TimingInformation(); + valid_result.timing_information->audio_start_time = kZeroTime; + valid_result.timing_information->audio_end_time = + base::TimeDelta::FromSeconds(2); + valid_result.timing_information->hypothesis_parts = + std::vector<media::HypothesisParts>(); + auto& hypothesis_parts = + valid_result.timing_information->hypothesis_parts.value(); + hypothesis_parts.emplace_back(std::vector<std::string>({"hello"}), + base::TimeDelta::FromSeconds(0)); + hypothesis_parts.emplace_back(std::vector<std::string>({"world"}), + base::TimeDelta::FromSeconds(1)); + std::vector<uint8_t> data = + media::mojom::SpeechRecognitionResult::Serialize(&valid_result); + media::SpeechRecognitionResult output; + EXPECT_TRUE(media::mojom::SpeechRecognitionResult::Deserialize( + std::move(data), &output)); + EXPECT_EQ(valid_result, output); +} + +} // namespace media
diff --git a/media/mojo/mojom/speech_recognition_service.mojom b/media/mojo/mojom/speech_recognition_service.mojom index d5ba43b0..0e9bede 100644 --- a/media/mojo/mojom/speech_recognition_service.mojom +++ b/media/mojo/mojom/speech_recognition_service.mojom
@@ -119,6 +119,38 @@ OnLanguageIdentificationEvent(LanguageIdentificationEvent event); }; +// The hypothesis parts that provides timing information for each word in +// recognized speech. +struct HypothesisParts { + // A section of the final transcription text. Either an entire word or single + // character (depending on the language) with adjacent punctuation. There will + // usually only be one value here. If formatting is enabled in the speech + // recognition, then the raw text will be included as the second element. + array<string> text; + + // Time offset from this event's |audio_start_time| defined below. We enforce + // the following invariant: 0 <= hypothesis_part_offset < |audio_end_time - + // audio_start_time|. + mojo_base.mojom.TimeDelta hypothesis_part_offset; +}; + +// The timing information for the transcript. +struct TimingInformation { + // Start time in audio time from the start of the SODA session. + // This time measures the amount of audio input into SODA. + mojo_base.mojom.TimeDelta audio_start_time; + + // Elapsed processed audio from first frame after preamble. + mojo_base.mojom.TimeDelta audio_end_time; + + // The timing information for each word/letter in the transription. + // HypothesisPartsInResult was introduced in min version 1 in + // chromeos/services/machine_learning/public/mojom/soda.mojom. Therefore, it + // must be optional. Hypothesis parts maybe non-empty optional containing a + // zero length vector if no words were spoken during the event's time span. + array<HypothesisParts> ? hypothesis_parts; +}; + // A speech recognition result created by the speech service and passed to the // browser. struct SpeechRecognitionResult { @@ -128,6 +160,12 @@ // locked in and the next result returned will not overlap with the previous // final result. bool is_final; + + // Timing information for the current transcription. |timing_information| is + // expected to be valid if: + // 1. speech recognition is provided by |CrosSodaClient| and + // 2. |is_final| is true. + TimingInformation? timing_information; }; // A language identification event created by the speech recognition service
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc index 785f2c9..265b7b3 100644 --- a/media/mojo/services/mojo_cdm_service.cc +++ b/media/mojo/services/mojo_cdm_service.cc
@@ -220,10 +220,11 @@ } } -void MojoCdmService::OnSessionClosed(const std::string& session_id) { +void MojoCdmService::OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason) { DVLOG(2) << __func__; if (client_) { - client_->OnSessionClosed(session_id); + client_->OnSessionClosed(session_id, reason); } }
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h index d6c32d1..bedc547 100644 --- a/media/mojo/services/mojo_cdm_service.h +++ b/media/mojo/services/mojo_cdm_service.h
@@ -98,7 +98,8 @@ CdmKeysInfo keys_info); void OnSessionExpirationUpdate(const std::string& session_id, base::Time new_expiry_time); - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason); // Callback for when |decryptor_| loses connectivity. void OnDecryptorConnectionError();
diff --git a/media/test/fake_encrypted_media.cc b/media/test/fake_encrypted_media.cc index cd5320c1..cb312065 100644 --- a/media/test/fake_encrypted_media.cc +++ b/media/test/fake_encrypted_media.cc
@@ -43,8 +43,9 @@ app_->OnSessionMessage(session_id, message_type, message, decryptor_.get()); } -void FakeEncryptedMedia::OnSessionClosed(const std::string& session_id) { - app_->OnSessionClosed(session_id); +void FakeEncryptedMedia::OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason) { + app_->OnSessionClosed(session_id, reason); } void FakeEncryptedMedia::OnSessionKeysChange(const std::string& session_id,
diff --git a/media/test/fake_encrypted_media.h b/media/test/fake_encrypted_media.h index 9e1e643a..8c942b1 100644 --- a/media/test/fake_encrypted_media.h +++ b/media/test/fake_encrypted_media.h
@@ -26,7 +26,8 @@ const std::vector<uint8_t>& message, AesDecryptor* decryptor) = 0; - virtual void OnSessionClosed(const std::string& session_id) = 0; + virtual void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason) = 0; virtual void OnSessionKeysChange(const std::string& session_id, bool has_additional_usable_key, @@ -43,11 +44,13 @@ FakeEncryptedMedia(AppBase* app); ~FakeEncryptedMedia(); CdmContext* GetCdmContext(); + // Callbacks for firing session events. Delegate to |app_|. void OnSessionMessage(const std::string& session_id, CdmMessageType message_type, const std::vector<uint8_t>& message); - void OnSessionClosed(const std::string& session_id); + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason reason); void OnSessionKeysChange(const std::string& session_id, bool has_additional_usable_key, CdmKeysInfo keys_info);
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 220d3e0..a09045a 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -239,7 +239,8 @@ CreatePromise(RESOLVED)); } - void OnSessionClosed(const std::string& session_id) override { + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason /*reason*/) override { EXPECT_EQ(current_session_id_, session_id); } @@ -326,7 +327,8 @@ FAIL() << "Unexpected Message"; } - void OnSessionClosed(const std::string& session_id) override { + void OnSessionClosed(const std::string& session_id, + CdmSessionClosedReason /*reason*/) override { EXPECT_FALSE(session_id.empty()); FAIL() << "Unexpected Closed"; }
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h index 86ff9a7..3975d01 100644 --- a/mojo/public/cpp/bindings/connector.h +++ b/mojo/public/cpp/bindings/connector.h
@@ -81,11 +81,21 @@ kSerializeBeforeDispatchForTesting, }; - // The Connector takes ownership of |message_pipe|. + // The Connector takes ownership of `message_pipe`. A Connector is essentially + // inert upon construction, though it may be used to send messages + // immediately. In order to receive incoming messages or error events, + // StartReceiving() must be called. + Connector(ScopedMessagePipeHandle message_pipe, + ConnectorConfig config, + const char* interface_name = "unknown interface"); + + // Same as above but automatically calls StartReceiving() with `runner` before + // returning. Connector(ScopedMessagePipeHandle message_pipe, ConnectorConfig config, scoped_refptr<base::SequencedTaskRunner> runner, const char* interface_name = "unknown interface"); + ~Connector() override; const char* interface_name() const { return interface_name_; } @@ -131,6 +141,18 @@ return error_; } + // Starts receiving on the Connector's message pipe, allowing incoming + // messages and error events to be dispatched. Once called, the Connector is + // effectively bound to `task_runner`. Initialization methods like + // `set_incoming_receiver` may be called before this, but if called after they + // must be called from the same sequence as `task_runner`. + // + // If `allow_woken_up_by_others` is true, the receiving sequence will allow + // this connector to process incoming messages during any sync wait by any + // Mojo object on the same sequence. + void StartReceiving(scoped_refptr<base::SequencedTaskRunner> task_runner, + bool allow_woken_up_by_others = false); + // Closes the pipe. The connector is put into a quiescent state. // // Please note that this method shouldn't be called unless it results from an @@ -303,8 +325,10 @@ // The quota checker associate with this connector, if any. scoped_refptr<internal::MessageQuotaChecker> quota_checker_; - base::Lock connected_lock_; - bool connected_ = true; + // Indicates whether the Connector is configured to actively read from its + // message pipe. As long as this is true, the Connector is only safe to + // destroy in sequence with `task_runner_` tasks. + bool is_receiving_ = false; // The tag used to track heap allocations that originated from a Watcher // notification.
diff --git a/mojo/public/cpp/bindings/lib/associated_receiver.cc b/mojo/public/cpp/bindings/lib/associated_receiver.cc index 98f820cc..221fbf1d 100644 --- a/mojo/public/cpp/bindings/lib/associated_receiver.cc +++ b/mojo/public/cpp/bindings/lib/associated_receiver.cc
@@ -74,7 +74,7 @@ void AssociateWithDisconnectedPipe(ScopedInterfaceEndpointHandle handle) { MessagePipe pipe; scoped_refptr<internal::MultiplexRouter> router = - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, false, base::SequencedTaskRunnerHandle::Get()); router->AssociateInterface(std::move(handle));
diff --git a/mojo/public/cpp/bindings/lib/binding_state.cc b/mojo/public/cpp/bindings/lib/binding_state.cc index fd20c1e5..1efeb07 100644 --- a/mojo/public/cpp/bindings/lib/binding_state.cc +++ b/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -122,8 +122,9 @@ : (has_sync_methods ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS : MultiplexRouter::SINGLE_INTERFACE); - router_ = MultiplexRouter::Create(std::move(receiver_state->pipe), config, - false, sequenced_runner, interface_name); + router_ = MultiplexRouter::CreateAndStartReceiving( + std::move(receiver_state->pipe), config, false, sequenced_runner, + interface_name); router_->SetConnectionGroup(std::move(receiver_state->connection_group)); endpoint_client_ = std::make_unique<InterfaceEndpointClient>(
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index daae5a3..3223c784 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -148,10 +148,8 @@ Connector::Connector(ScopedMessagePipeHandle message_pipe, ConnectorConfig config, - scoped_refptr<base::SequencedTaskRunner> runner, const char* interface_name) : message_pipe_(std::move(message_pipe)), - task_runner_(std::move(runner)), error_(false), force_immediate_dispatch_(!EnableTaskPerMessage()), outgoing_serialization_mode_(g_default_outgoing_serialization_mode), @@ -166,17 +164,14 @@ #endif weak_self_ = weak_factory_.GetWeakPtr(); +} - DETACH_FROM_SEQUENCE(sequence_checker_); - - // Even though we don't have an incoming receiver, we still want to monitor - // the message pipe to know if is closed or encounters an error. - if (task_runner_->RunsTasksInCurrentSequence()) { - WaitToReadMore(); - } else { - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&Connector::WaitToReadMore, weak_self_)); - } +Connector::Connector(ScopedMessagePipeHandle message_pipe, + ConnectorConfig config, + scoped_refptr<base::SequencedTaskRunner> runner, + const char* interface_name) + : Connector(std::move(message_pipe), config, interface_name) { + StartReceiving(std::move(runner)); } Connector::~Connector() { @@ -187,16 +182,10 @@ quota_checker_->GetMaxQuotaUsage()); } - { - // Allow for quick destruction on any sequence if the pipe is already - // closed. - base::AutoLock lock(connected_lock_); - if (!connected_) - return; + if (is_receiving_) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + CancelWait(); } - - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - CancelWait(); } void Connector::SetOutgoingSerializationMode(OutgoingSerializationMode mode) { @@ -209,6 +198,22 @@ incoming_serialization_mode_ = mode; } +void Connector::StartReceiving( + scoped_refptr<base::SequencedTaskRunner> task_runner, + bool allow_woken_up_by_others) { + DCHECK(!task_runner_); + task_runner_ = std::move(task_runner); + allow_woken_up_by_others_ = allow_woken_up_by_others; + if (task_runner_->RunsTasksInCurrentSequence()) { + WaitToReadMore(); + } else { + DETACH_FROM_SEQUENCE(sequence_checker_); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&Connector::WaitToReadMore, weak_factory_.GetWeakPtr())); + } +} + void Connector::CloseMessagePipe() { // Throw away the returned message pipe. PassMessagePipe(); @@ -223,8 +228,6 @@ weak_factory_.InvalidateWeakPtrs(); sync_handle_watcher_callback_count_ = 0; - base::AutoLock lock(connected_lock_); - connected_ = false; return message_pipe; } @@ -331,9 +334,11 @@ if (!message->is_serialized()) { // The caller is sending an unserialized message. If we haven't set up a // remoteness tracker yet, do so now. See PrefersSerializedMessages() above - // for more details. + // for more details. Note that if the Connector is not yet bound to a + // TaskRunner and activaly reading the pipe, we don't bother setting this up + // yet. DCHECK_EQ(outgoing_serialization_mode_, OutgoingSerializationMode::kLazy); - if (!peer_remoteness_tracker_) { + if (!peer_remoteness_tracker_ && task_runner_) { peer_remoteness_tracker_.emplace( message_pipe_.get(), MOJO_HANDLE_SIGNAL_PEER_REMOTE, task_runner_); } @@ -437,6 +442,7 @@ } void Connector::WaitToReadMore() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); CHECK(!paused_); DCHECK(!handle_watcher_); @@ -466,6 +472,8 @@ EnsureSyncWatcherExists(); sync_watcher_->AllowWokenUpBySyncWatchOnSameThread(); } + + is_receiving_ = true; } uint64_t Connector::QueryPendingMessageCount() const { @@ -627,6 +635,8 @@ } void Connector::CancelWait() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + is_receiving_ = false; peer_remoteness_tracker_.reset(); handle_watcher_.reset(); sync_watcher_.reset();
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc index 7f095b7e..ea1c937 100644 --- a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc +++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
@@ -98,6 +98,14 @@ // The version is only queried from the client so the value passed here // will not be used. 0u, interface_name); + + // Note that we defer this until after attaching the endpoint. This is in case + // `runner_` does not run tasks in the current sequence but MultiplexRouter is + // in SINGLE_INTERFACE mode. In that case, MultiplexRouter elides some + // internal synchronization, so we need to ensure that messages aren't + // processed by the router before the endpoint above is fully attached. + router_->StartReceiving(); + return true; }
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc index f6b62b0b..b6b7f46 100644 --- a/mojo/public/cpp/bindings/lib/multiplex_router.cc +++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -338,16 +338,22 @@ bool set_interface_id_namespace_bit, scoped_refptr<base::SequencedTaskRunner> runner, const char* primary_interface_name) { - auto router = base::MakeRefCounted<MultiplexRouter>( + return base::MakeRefCounted<MultiplexRouter>( base::PassKey<MultiplexRouter>(), std::move(message_pipe), config, set_interface_id_namespace_bit, runner, primary_interface_name); - if (runner->RunsTasksInCurrentSequence()) { - router->BindToCurrentSequence(); - } else { - runner->PostTask( - FROM_HERE, - base::BindOnce(&MultiplexRouter::BindToCurrentSequence, router)); - } +} + +// static +scoped_refptr<MultiplexRouter> MultiplexRouter::CreateAndStartReceiving( + ScopedMessagePipeHandle message_pipe, + Config config, + bool set_interface_id_namespace_bit, + scoped_refptr<base::SequencedTaskRunner> runner, + const char* primary_interface_name) { + auto router = + Create(std::move(message_pipe), config, set_interface_id_namespace_bit, + runner, primary_interface_name); + router->StartReceiving(); return router; } @@ -365,31 +371,13 @@ connector_(std::move(message_pipe), config == MULTI_INTERFACE ? Connector::MULTI_THREADED_SEND : Connector::SINGLE_THREADED_SEND, - std::move(runner), primary_interface_name), control_message_handler_(this), control_message_proxy_(&connector_) { - DETACH_FROM_SEQUENCE(sequence_checker_); if (config_ == MULTI_INTERFACE) lock_.emplace(); -} -void MultiplexRouter::BindToCurrentSequence() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (config_ == SINGLE_INTERFACE_WITH_SYNC_METHODS || - config_ == MULTI_INTERFACE) { - // Always participate in sync handle watching in multi-interface mode, - // because even if it doesn't expect sync requests during sync handle - // watching, it may still need to dispatch messages to associated endpoints - // on a different sequence. - connector_.AllowWokenUpBySyncWatchOnSameThread(); - } connector_.set_incoming_receiver(&dispatcher_); - connector_.set_connection_error_handler( - base::BindOnce(&MultiplexRouter::OnPipeConnectionError, - base::Unretained(this), false /* force_async_dispatch */)); scoped_refptr<internal::MessageQuotaChecker> quota_checker = internal::MessageQuotaChecker::MaybeCreate(); @@ -401,7 +389,6 @@ header_validator_ = header_validator.get(); dispatcher_.SetValidator(std::move(header_validator)); - const char* primary_interface_name = connector_.interface_name(); if (primary_interface_name) { header_validator_->SetDescription(base::JoinString( {primary_interface_name, "[primary] MessageHeaderValidator"}, " ")); @@ -410,6 +397,23 @@ } } +void MultiplexRouter::StartReceiving() { + connector_.set_connection_error_handler( + base::BindOnce(&MultiplexRouter::OnPipeConnectionError, + base::Unretained(this), false /* force_async_dispatch */)); + + // Always participate in sync handle watching in multi-interface mode, + // because even if it doesn't expect sync requests during sync handle + // watching, it may still need to dispatch messages to associated endpoints + // on a different sequence. + const bool allow_woken_up_by_others = + config_ == SINGLE_INTERFACE_WITH_SYNC_METHODS || + config_ == MULTI_INTERFACE; + + DETACH_FROM_SEQUENCE(sequence_checker_); + connector_.StartReceiving(task_runner_, allow_woken_up_by_others); +} + MultiplexRouter::~MultiplexRouter() { MayAutoLock locker(&lock_);
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h index d61f3ae..3d3bbb16 100644 --- a/mojo/public/cpp/bindings/lib/multiplex_router.h +++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -76,8 +76,10 @@ // If `set_interface_id_namespace_bit` is true, the interface IDs generated by // this router will have the highest bit set. // - // NOTE: CloseMessagePipe() or PassMessagePipe() MUST be called on the - // `runner` sequence before this object is destroyed. + // Note that the MultiplexRouter will not initially receive any messages or + // disconnect events until StartReceiving() is explicitly called. To create a + // MultiplexRouter which calls this automatically at construction time, use + // CreateAndStartReceiving(). static scoped_refptr<MultiplexRouter> Create( ScopedMessagePipeHandle message_pipe, Config config, @@ -85,6 +87,23 @@ scoped_refptr<base::SequencedTaskRunner> runner, const char* primary_interface_name = "unknown interface"); + // Same as above, but automatically calls StartReceiving() before returning. + // If `runner` does not run tasks in sequence with the caller, the returned + // MultiplexRouter may already begin receiving messages and events on `runner` + // before this call returns. + static scoped_refptr<MultiplexRouter> CreateAndStartReceiving( + ScopedMessagePipeHandle message_pipe, + Config config, + bool set_interface_id_namespace_bit, + scoped_refptr<base::SequencedTaskRunner> runner, + const char* primary_interface_name = "unknown interface"); + + // Starts receiving messages on the MultiplexRouter. Once this is called, + // CloseMessagePipe() or PassMessagePipe() MUST be called in sequence with + // the MultiplexRouter's `task_runner_` prior to destroying the + // MultiplexRouter. + void StartReceiving(); + MultiplexRouter(base::PassKey<MultiplexRouter>, ScopedMessagePipeHandle message_pipe, Config config, @@ -188,9 +207,6 @@ ~MultiplexRouter() override; - // Completes initialization of the MultiplexRouter. - void BindToCurrentSequence(); - // Indicates whether `message` can unblock any active external sync waiter. bool CanUnblockExternalSyncWait(const Message& message);
diff --git a/mojo/public/cpp/bindings/pending_associated_receiver.h b/mojo/public/cpp/bindings/pending_associated_receiver.h index 487cf5c..fb6837c 100644 --- a/mojo/public/cpp/bindings/pending_associated_receiver.h +++ b/mojo/public/cpp/bindings/pending_associated_receiver.h
@@ -107,11 +107,11 @@ MessagePipe pipe; scoped_refptr<internal::MultiplexRouter> router0 = - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, false, base::SequencedTaskRunnerHandle::Get()); scoped_refptr<internal::MultiplexRouter> router1 = - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE, true, base::SequencedTaskRunnerHandle::Get());
diff --git a/mojo/public/cpp/bindings/pending_associated_remote.h b/mojo/public/cpp/bindings/pending_associated_remote.h index cd4d28c..bb68431 100644 --- a/mojo/public/cpp/bindings/pending_associated_remote.h +++ b/mojo/public/cpp/bindings/pending_associated_remote.h
@@ -103,11 +103,11 @@ MessagePipe pipe; scoped_refptr<internal::MultiplexRouter> router0 = - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, false, base::SequencedTaskRunnerHandle::Get()); scoped_refptr<internal::MultiplexRouter> router1 = - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE, true, base::SequencedTaskRunnerHandle::Get());
diff --git a/mojo/public/cpp/bindings/pending_receiver.h b/mojo/public/cpp/bindings/pending_receiver.h index c3c74b6..9ca1d24 100644 --- a/mojo/public/cpp/bindings/pending_receiver.h +++ b/mojo/public/cpp/bindings/pending_receiver.h
@@ -92,7 +92,7 @@ return request; } - // Indicates whether the PendingReceiver is valid, meaning it can ne used to + // Indicates whether the PendingReceiver is valid, meaning it can be used to // bind a Receiver that wants to begin dispatching method calls made by the // entangled Remote. bool is_valid() const { return state_.pipe.is_valid(); }
diff --git a/mojo/public/cpp/bindings/receiver.h b/mojo/public/cpp/bindings/receiver.h index 0888f0d..87818aa 100644 --- a/mojo/public/cpp/bindings/receiver.h +++ b/mojo/public/cpp/bindings/receiver.h
@@ -52,7 +52,7 @@ using ImplPointerType = typename ImplRefTraits::PointerType; // Constructs an unbound Receiver linked to |impl| for the duration of the - // Receive's lifetime. The Receiver can be bound later by calling |Bind()| or + // Receiver's lifetime. The Receiver can be bound later by calling |Bind()| or // |BindNewPipeAndPassRemote()|. An unbound Receiver does not schedule any // asynchronous tasks. explicit Receiver(ImplPointerType impl) : internal_state_(std::move(impl)) {} @@ -139,7 +139,7 @@ return remote; } - // Like above, but the returne PendingRemote has the version annotated. + // Like above, but the returned PendingRemote has the version annotated. PendingRemote<Interface> BindNewPipeAndPassRemoteWithVersion( scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) WARN_UNUSED_RESULT {
diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc index b503e77..0b50480b 100644 --- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc +++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
@@ -117,12 +117,12 @@ void CreateRouterPair(scoped_refptr<MultiplexRouter>* router0, scoped_refptr<MultiplexRouter>* router1) { MessagePipe pipe; - *router0 = MultiplexRouter::Create(std::move(pipe.handle0), - MultiplexRouter::MULTI_INTERFACE, true, - main_runner_); - *router1 = MultiplexRouter::Create(std::move(pipe.handle1), - MultiplexRouter::MULTI_INTERFACE, false, - main_runner_); + *router0 = MultiplexRouter::CreateAndStartReceiving( + std::move(pipe.handle0), MultiplexRouter::MULTI_INTERFACE, true, + main_runner_); + *router1 = MultiplexRouter::CreateAndStartReceiving( + std::move(pipe.handle1), MultiplexRouter::MULTI_INTERFACE, false, + main_runner_); } void CreateIntegerSenderWithExistingRouters(
diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc index f4dfff31..41f7c26 100644 --- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc +++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
@@ -189,11 +189,11 @@ TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) { MessagePipe pipe; scoped_refptr<internal::MultiplexRouter> router0( - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle0), internal::MultiplexRouter::SINGLE_INTERFACE, true, base::ThreadTaskRunnerHandle::Get())); scoped_refptr<internal::MultiplexRouter> router1( - internal::MultiplexRouter::Create( + internal::MultiplexRouter::CreateAndStartReceiving( std::move(pipe.handle1), internal::MultiplexRouter::SINGLE_INTERFACE, false, base::ThreadTaskRunnerHandle::Get()));
diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc index ea697d8..af60dfd 100644 --- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc +++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
@@ -33,12 +33,12 @@ void SetUp() override { MessagePipe pipe; - router0_ = MultiplexRouter::Create(std::move(pipe.handle0), - MultiplexRouter::MULTI_INTERFACE, false, - base::ThreadTaskRunnerHandle::Get()); - router1_ = MultiplexRouter::Create(std::move(pipe.handle1), - MultiplexRouter::MULTI_INTERFACE, true, - base::ThreadTaskRunnerHandle::Get()); + router0_ = MultiplexRouter::CreateAndStartReceiving( + std::move(pipe.handle0), MultiplexRouter::MULTI_INTERFACE, false, + base::ThreadTaskRunnerHandle::Get()); + router1_ = MultiplexRouter::CreateAndStartReceiving( + std::move(pipe.handle1), MultiplexRouter::MULTI_INTERFACE, true, + base::ThreadTaskRunnerHandle::Get()); ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0_, &endpoint1_); auto id = router0_->AssociateInterface(std::move(endpoint1_));
diff --git a/mojo/public/js/mojo_bindings_resources.grd b/mojo/public/js/mojo_bindings_resources.grd index cca7888..81073dd 100644 --- a/mojo/public/js/mojo_bindings_resources.grd +++ b/mojo/public/js/mojo_bindings_resources.grd
@@ -95,6 +95,11 @@ use_base_dir="false" resource_path="mojo/mojo/public/mojom/base/text_direction.mojom-webui.js" type="BINDATA" /> + <include name="IDR_MOJO_TOKEN_MOJOM_WEBUI_JS" + file="${root_gen_dir}/mojom-webui/mojo/public/mojom/base/token.mojom-webui.js" + use_base_dir="false" + resource_path="mojo/mojo/public/mojom/base/token.mojom-webui.js" + type="BINDATA" /> <include name="IDR_MOJO_UNGUESSABLE_TOKEN_MOJOM_WEBUI_JS" file="${root_gen_dir}/mojom-webui/mojo/public/mojom/base/unguessable_token.mojom-webui.js" use_base_dir="false"
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index 4183288f..ede99f58 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -619,7 +619,6 @@ std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter); included_cookies.reserve(cookie_ptrs.size()); - std::vector<CanonicalCookie*> included_cookie_ptrs; FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookies, &excluded_cookies); }
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index ce53c75..8ef5331 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc
@@ -817,6 +817,7 @@ void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate:: OnPathValidationFailure( std::unique_ptr<quic::QuicPathValidationContext> context) { + session_->connection()->OnPathValidationFailureAtClient(); // Note that socket, packet writer, and packet reader in |context| will be // discarded. auto* chrome_context = @@ -843,6 +844,7 @@ void QuicChromiumClientSession::PortMigrationValidationResultDelegate:: OnPathValidationFailure( std::unique_ptr<quic::QuicPathValidationContext> context) { + session_->connection()->OnPathValidationFailureAtClient(); // Note that socket, packet writer, and packet reader in |context| will be // discarded. auto* chrome_context = @@ -2183,9 +2185,13 @@ weak_factory_.GetWeakPtr(), error_code, connection()->writer())); - // Store packet in the session since the actual migration and packet rewrite - // can happen via this posted task or via an async network notification. - packet_ = std::move(packet); + // Only save packet from the old path for retransmission on the new path when + // the connection ID does not change. + if (!connection()->connection_migration_use_new_cid()) { + // Store packet in the session since the actual migration and packet rewrite + // can happen via this posted task or via an async network notification. + packet_ = std::move(packet); + } ignore_read_error_ = true; // Cause the packet writer to return ERR_IO_PENDING and block so @@ -2501,7 +2507,7 @@ /*is_success=*/false); }); - if (version().HasIetfQuicFrames() && connection()->use_path_validator()) { + if (connection()->connection_migration_use_new_cid()) { auto* context = static_cast<QuicChromiumPathValidationContext*>( connection()->GetPathValidationContext()); @@ -2580,7 +2586,7 @@ "disconnected_network", disconnected_network); // Stop probing the disconnected network if there is one. - if (version().HasIetfQuicFrames() && connection()->use_path_validator()) { + if (connection()->connection_migration_use_new_cid()) { auto* context = static_cast<QuicChromiumPathValidationContext*>( connection()->GetPathValidationContext()); if (context && context->network() == disconnected_network && @@ -2706,7 +2712,7 @@ } // Cancel probing on |network| if there is any. - if (version().HasIetfQuicFrames() && connection()->use_path_validator()) { + if (connection()->connection_migration_use_new_cid()) { auto* context = static_cast<QuicChromiumPathValidationContext*>( connection()->GetPathValidationContext()); if (context && context->network() == network && @@ -3041,7 +3047,8 @@ // Abort probing if connection migration is disabled by config. if (config()->DisableConnectionMigration() || - (version().HasIetfQuicFrames() && !connection()->use_path_validator())) { + (version().HasIetfQuicFrames() && + !connection()->connection_migration_use_new_cid())) { DVLOG(1) << "Client disables probing network with connection migration " << "disabled by config"; HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG, @@ -3057,7 +3064,7 @@ NetworkChangeNotifier::NetworkHandle network, const quic::QuicSocketAddress& peer_address) { // Check if probing manager is probing the same path. - if (version().HasIetfQuicFrames() && connection()->use_path_validator()) { + if (connection()->connection_migration_use_new_cid()) { auto* context = static_cast<QuicChromiumPathValidationContext*>( connection()->GetPathValidationContext()); if (context && context->network() == network && @@ -3097,7 +3104,8 @@ rtt_ms = kDefaultRTTMilliSecs; int timeout_ms = rtt_ms * 2; - if (connection()->use_path_validator() && version().HasIetfQuicFrames()) { + if (connection()->connection_migration_use_new_cid() && + version().HasIetfQuicFrames()) { probing_reader->StartReading(); path_validation_writer_delegate_.set_network(network); path_validation_writer_delegate_.set_peer_address(peer_address); @@ -3586,8 +3594,6 @@ if (!MigrateToSocket(ToQuicSocketAddress(self_address), ToQuicSocketAddress(peer_address), std::move(socket), std::move(new_reader), std::move(new_writer))) { - HistogramAndLogMigrationFailure(MIGRATION_STATUS_TOO_MANY_CHANGES, - connection_id(), "Too many changes"); if (close_session_on_error) { if (migrate_session_on_network_change_v2_) { CloseSessionOnErrorLater( @@ -3619,6 +3625,8 @@ // write error events, and path degrading on original network. if (!migrate_session_on_network_change_v2_ && sockets_.size() >= kMaxReadersPerQuicSession) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_TOO_MANY_CHANGES, + connection_id(), "Too many changes"); return false; } @@ -3628,8 +3636,14 @@ // WriteToNewSocket completes. DVLOG(1) << "Force blocking the packet writer"; writer->set_force_write_blocked(true); - MigratePath(self_address, peer_address, writer.release(), - /*owns_writer=*/true); + if (!MigratePath(self_address, peer_address, writer.release(), + /*owns_writer=*/true)) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_UNUSED_CONNECTION_ID, + connection_id(), + "No unused server connection ID"); + DVLOG(1) << "MigratePath fails as there is no CID available"; + return false; + } // Post task to write the pending packet or a PING packet to the new // socket. This avoids reentrancy issues if there is a write error
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h index 538ffda..853970a 100644 --- a/net/quic/quic_chromium_client_session.h +++ b/net/quic/quic_chromium_client_session.h
@@ -121,6 +121,7 @@ MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED, MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED, MIGRATION_STATUS_IDLE_MIGRATION_TIMEOUT, + MIGRATION_STATUS_NO_UNUSED_CONNECTION_ID, MIGRATION_STATUS_MAX };
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 6e5ea81..2d15f21 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -244,6 +244,18 @@ &crypto_client_stream_factory_, &context_); } + void SetIetfConnectionMigrationFlagsAndConnectionOptions() { + FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; + FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + FLAGS_quic_reloadable_flag_quic_use_connection_id_on_default_path_v2 = true; + FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3 = true; + FLAGS_quic_reloadable_flag_quic_group_path_response_and_challenge_sending_closer = + true; + FLAGS_quic_reloadable_flag_quic_drop_unsent_path_response = true; + FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2 = true; + quic_params_->connection_options.push_back(quic::kRVCM); + } + void InitializeConnectionMigrationV2Test( NetworkChangeNotifier::NetworkList connected_networks) { scoped_mock_network_change_notifier_ = @@ -256,11 +268,25 @@ quic_params_->migrate_sessions_early_v2 = true; quic_params_->allow_port_migration = false; socket_factory_ = std::make_unique<TestConnectionMigrationSocketFactory>(); - FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; - FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + SetIetfConnectionMigrationFlagsAndConnectionOptions(); Initialize(); } + void MaybeMakeNewConnectionIdAvailableToSession( + const quic::QuicConnectionId& new_cid, + quic::QuicSession* session) { + if (version_.HasIetfQuicFrames()) { + quic::QuicNewConnectionIdFrame new_cid_frame; + new_cid_frame.connection_id = new_cid; + new_cid_frame.sequence_number = 1u; + new_cid_frame.retire_prior_to = 0u; + new_cid_frame.stateless_reset_token = + quic::QuicUtils::GenerateStatelessResetToken( + new_cid_frame.connection_id); + session->connection()->OnNewConnectionIdFrame(new_cid_frame); + } + } + std::unique_ptr<HttpStream> CreateStream(QuicStreamRequest* request) { std::unique_ptr<QuicChromiumClientSession::Handle> session = request->ReleaseSessionHandle(); @@ -2697,6 +2723,11 @@ // Set up the second socket data provider that is used after migration. // The response to the earlier request is read on the new socket. + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } MockQuicData quic_data2(version_); // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( @@ -2765,6 +2796,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -2909,6 +2941,11 @@ // Set up the second socket data provider that is used after migration. // The response to the earlier request is read on the new socket. + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } MockQuicData quic_data2(version_); // First connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( @@ -2930,10 +2967,13 @@ if (VersionUsesHttp3(version_.transport_version)) { quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( packet_num++, 1, 1, 1, {1, 2})); + quic_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRetireConnectionIdPacket( + packet_num++, true, 2, 1, 0u)); quic_data2.AddWrite( - SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( - packet_num++, false, GetQpackDecoderStreamId(), 2, 2, - false, StreamCancellationQpackDecoderInstruction(0))); + SYNCHRONOUS, client_maker_.MakeDataPacket( + packet_num++, GetQpackDecoderStreamId(), false, false, + StreamCancellationQpackDecoderInstruction(0))); quic_data2.AddWrite( SYNCHRONOUS, client_maker_.MakeRstPacket( @@ -2978,6 +3018,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -3201,6 +3242,13 @@ } // Set up the second socket data provider that is used for probing. + quic::QuicConnectionId cid_on_old_path = + quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } MockQuicData quic_data1(version_); // Connectivity probe to be sent on the new path. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( @@ -3232,7 +3280,15 @@ // Ping packet to send after migration is completed. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, false)); + if (VersionUsesHttp3(version_.transport_version)) { + quic_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_num++, false, 0u)); + } } else { + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_old_path); + } if (version_.UsesTls()) { if (VersionUsesHttp3(version_.transport_version)) { socket_data.AddWrite( @@ -3306,6 +3362,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Trigger connection migration. Session will start to probe the alternative // network. Although there is a non-migratable stream, session will still be @@ -3421,6 +3478,10 @@ client_maker_.set_save_packet_frames(true); MockQuicData failed_socket_data(version_); + quic::QuicConnectionId cid_on_old_path = + quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); MockQuicData socket_data(version_); if (migrate_idle_sessions) { failed_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); @@ -3444,16 +3505,27 @@ failed_socket_data.AddSocketDataToFactory(socket_factory_.get()); // Set up second socket data provider that is used after migration. + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. if (version_.UsesHttp3()) { socket_data.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( {3, 1, 2}, packet_num++, true)); + // Ping packet to send after migration. + socket_data.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, + /*include_version=*/false)); + socket_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, 0u)); + } else { + // Ping packet to send after migration. + socket_data.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - // Ping packet to send after migration. - socket_data.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); socket_data.AddSocketDataToFactory(socket_factory_.get()); } else { socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); @@ -3499,11 +3571,12 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Trigger connection migration. Since there is a non-migratable stream, // this should cause a RST_STREAM frame to be emitted with // quic::QUIC_STREAM_CANCELLED error code. - // If migate idle session, the connection will then be migrated to the + // If migrate idle session, the connection will then be migrated to the // alternate network. Otherwise, the connection will be closed. scoped_mock_network_change_notifier_->mock_network_change_notifier() ->NotifyNetworkDisconnected(kDefaultNetworkForTests); @@ -3615,8 +3688,13 @@ } socket_data.AddSocketDataToFactory(socket_factory_.get()); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); MockQuicData quic_data1(version_); if (migrate_idle_sessions) { + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Set up the second socket data provider that is used for probing. // Connectivity probe to be sent on the new path. quic_data1.AddWrite( @@ -3632,6 +3710,9 @@ // already sent on the new address, ping will no longer be sent. quic_data1.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( packet_num++, 1, 1, 1, {1})); + quic_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_num++, false, 0u)); } else { // Ping packet to send after migration is completed. quic_data1.AddWrite( @@ -3658,6 +3739,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_FALSE(session->HasActiveRequestStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Trigger connection migration. scoped_mock_network_change_notifier_->mock_network_change_notifier() @@ -3703,7 +3785,12 @@ default_socket_data.AddSocketDataToFactory(socket_factory_.get()); MockQuicData alternate_socket_data(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); if (migrate_idle_sessions) { + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Set up second socket data provider that is used after migration. alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. @@ -3711,11 +3798,19 @@ alternate_socket_data.AddWrite( SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, packet_num++, true)); + // Ping packet to send after migration. + alternate_socket_data.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, + /*include_version=*/false)); + alternate_socket_data.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_num++, true, 0u)); + } else { + // Ping packet to send after migration. + alternate_socket_data.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - // Ping packet to send after migration. - alternate_socket_data.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); } @@ -3733,7 +3828,8 @@ EXPECT_TRUE(stream.get()); // Ensure that session is active. - EXPECT_TRUE(HasActiveSession(host_port_pair_)); + auto* session = GetActiveSession(host_port_pair_); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Trigger connection migration. Since there are no active streams, // the session will be closed. @@ -3820,6 +3916,9 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -3833,14 +3932,24 @@ // Set up second socket data provider that is used after migration. // The response to the earlier request is read on this new socket. MockQuicData socket_data1(version_); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } if (version_.UsesHttp3()) { socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( {1, 2}, packet_number++, true)); + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_number++, + /*include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_number++, false, 0u)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_number++, + /*include_version=*/true)); } - socket_data1.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_number++, /*include_version=*/true)); socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( @@ -3962,6 +4071,9 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -3983,14 +4095,24 @@ // Set up second socket data provider that is used after migration. // The response to the earlier request is read on this new socket. MockQuicData socket_data1(version_); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } if (version_.UsesHttp3()) { socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( {1, 2}, packet_num++, true)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_num++, false, 0u)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - socket_data1.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( @@ -4092,6 +4214,11 @@ // Set up the second socket data provider that is used for probing on the // alternate network. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_number++, true)); @@ -4110,6 +4237,9 @@ if (version_.UsesHttp3()) { quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( packet_number++, 1, 4, 1, {1, 2})); + quic_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, 0u)); } else { quic_data2.AddWrite(ASYNC, client_maker_.MakeAckPacket(packet_number++, 4, 1)); @@ -4165,6 +4295,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -4308,6 +4439,11 @@ // Set up the second socket data provider that is used after migration. // The response to the earlier request is read on the new socket. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_number++, true)); @@ -4320,6 +4456,8 @@ // already sent on the new address, ping will no longer be sent. quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( packet_number++, 1, 1, 1, {1, 2})); + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeRetireConnectionIdPacket( + packet_number++, true, 0u)); } else { // Ping packet to send after migration is completed. quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndPingPacket( @@ -4376,6 +4514,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -4509,15 +4648,34 @@ ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, true)); quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. - quic_data1.AddSocketDataToFactory(socket_factory_.get()); // Set up the second socket data provider that is used for path validation. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_old_path = + quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); + ++packet_number; // Account for the packet encountering write error. quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // Pause quic_data2.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket(1, false)); + + // Connection ID is retired on the old path. + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_old_path); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, + /*largest_received=*/1, /*smallest_received=*/1, + /*sequence_number=*/1u)); + } + + quic_data1.AddSocketDataToFactory(socket_factory_.get()); quic_data2.AddSocketDataToFactory(socket_factory_.get()); // Create request and QuicHttpStream. @@ -4546,6 +4704,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -4615,6 +4774,10 @@ scoped_mock_network_change_notifier_->mock_network_change_notifier() ->QueueNetworkMadeDefault(kDefaultNetworkForTests); + quic::QuicConnectionId cid_on_path1 = + quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()); + quic::QuicConnectionId cid_on_path2 = quic::test::TestConnectionId(12345678); + int packet_number = 1; MockQuicData quic_data1(version_); quic_data1.AddWrite(SYNCHRONOUS, @@ -4630,26 +4793,34 @@ ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, true)); quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. - quic_data1.AddSocketDataToFactory(socket_factory_.get()); // Set up the second socket data provider that is used for path validation. MockQuicData quic_data2(version_); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_path2); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // Pause quic_data2.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket(1, false)); - quic_data2.AddSocketDataToFactory(socket_factory_.get()); + packet_number++; // Account for packet encountering write error. - packet_number++; + // Connection ID is retired on the old path. + client_maker_.set_connection_id(cid_on_path1); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, + /*largest_received=*/1, /*smallest_received=*/1, + /*sequence_number=*/1u)); + // A socket will be created for a new path, but there would be no write + // due to lack of new connection ID. MockQuicData quic_data3(version_); - // Connectivity probe to be sent on the new path. - quic_data3.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( - packet_number++, true)); - quic_data3.AddRead(ASYNC, ERR_IO_PENDING); // Pause - quic_data3.AddRead(ASYNC, - server_maker_.MakeConnectivityProbingPacket(1, false)); + quic_data3.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Pause + + quic_data1.AddSocketDataToFactory(socket_factory_.get()); + quic_data2.AddSocketDataToFactory(socket_factory_.get()); quic_data3.AddSocketDataToFactory(socket_factory_.get()); // Create request and QuicHttpStream. @@ -4678,6 +4849,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_path2, session); // Send GET request on stream. HttpResponseInfo response; @@ -4711,10 +4883,10 @@ base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); EXPECT_EQ(base::TimeDelta(), next_task_delay); task_runner->FastForwardBy(next_task_delay); - // Verify that the task is executed, but since a new path validation is under - // way, it won't be cancelled. + // Verify that the task is executed. EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); - EXPECT_TRUE(session->connection()->HasPendingPathValidation()); + // No pending path validation as there is no connection ID available. + EXPECT_FALSE(session->connection()->HasPendingPathValidation()); EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); quic_data1.Resume(); @@ -4739,8 +4911,7 @@ return; } quic_params_->allow_port_migration = true; - FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; - FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + SetIetfConnectionMigrationFlagsAndConnectionOptions(); socket_factory_ = std::make_unique<TestPortMigrationSocketFactory>(); Initialize(); @@ -4905,8 +5076,7 @@ return; } quic_params_->allow_port_migration = true; - FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; - FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + SetIetfConnectionMigrationFlagsAndConnectionOptions(); socket_factory_ = std::make_unique<TestPortMigrationSocketFactory>(); Initialize(); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -4940,6 +5110,11 @@ // Set up the second socket data provider that is used for migration probing. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_number, true)); @@ -4974,6 +5149,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -5032,8 +5208,7 @@ mock_ncn->ForceNetworkHandlesSupported(); mock_ncn->SetConnectedNetworksList({kDefaultNetworkForTests}); quic_params_->allow_port_migration = true; - FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; - FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + SetIetfConnectionMigrationFlagsAndConnectionOptions(); socket_factory_ = std::make_unique<TestPortMigrationSocketFactory>(); Initialize(); @@ -5104,8 +5279,7 @@ // Enable migration on network change. quic_params_->migrate_sessions_on_network_change_v2 = true; quic_params_->allow_port_migration = true; - FLAGS_quic_reloadable_flag_quic_pass_path_response_to_validator = true; - FLAGS_quic_reloadable_flag_quic_send_path_response2 = true; + SetIetfConnectionMigrationFlagsAndConnectionOptions(); socket_factory_ = std::make_unique<TestPortMigrationSocketFactory>(); Initialize(); @@ -5141,6 +5315,12 @@ // Set up the second socket data provider that is used after migration. // The response to the earlier request is read on the new socket. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version) && + FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_number++, true)); @@ -5157,11 +5337,27 @@ 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (VersionUsesHttp3(version_.transport_version)) { - quic_data2.AddWrite( - SYNCHRONOUS, - client_maker_.MakeAckAndDataPacket( - packet_number++, false, GetQpackDecoderStreamId(), 2, 2, false, - StreamCancellationQpackDecoderInstruction(0))); + if (FLAGS_quic_reloadable_flag_quic_connection_migration_use_new_cid_v2) { + quic_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, + /*largest_received=*/2, + /*smallest_received=*/1, /*sequence_number=*/0u)); + quic_data2.AddWrite( + SYNCHRONOUS, + client_maker_.MakeDataPacket( + packet_number++, GetQpackDecoderStreamId(), + /*should_include_version=*/false, + /*fin=*/false, StreamCancellationQpackDecoderInstruction(0))); + } else { + quic_data2.AddWrite( + SYNCHRONOUS, + client_maker_.MakeAckAndDataPacket( + packet_number++, /*include_version=*/false, + GetQpackDecoderStreamId(), + /*largest_received=*/2, /*smallest_received=*/2, /*fin=*/false, + StreamCancellationQpackDecoderInstruction(0))); + } quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeRstPacket( packet_number++, false, @@ -5202,6 +5398,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -5270,6 +5467,9 @@ EXPECT_EQ(base::TimeDelta(), next_task_delay); task_runner->FastForwardBy(next_task_delay); + // Fire any outstanding quic alarms. + base::RunLoop().RunUntilIdle(); + // Response headers are received over the new port. EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_EQ(200, response.headers->response_code()); @@ -5776,6 +5976,11 @@ // Set up the second socket data provider that is used after migration. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_number++, false)); @@ -5796,6 +6001,10 @@ quic_data2.AddWrite(ASYNC, client_maker_.MakePingPacket(packet_number++, false)); } + if (version_.UsesHttp3()) { + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeRetireConnectionIdPacket( + packet_number++, false, 0u)); + } server_maker_.Reset(); quic_data2.AddRead( ASYNC, @@ -5832,6 +6041,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -5957,6 +6167,11 @@ // Set up the second socket data provider that is used after migration. // The response to the earlier request is read on the new socket. MockQuicData quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_num++, true)); @@ -5969,6 +6184,8 @@ // already sent on the new address, ping will no longer be sent. quic_data2.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( packet_num++, 1, 1, 1, {1, 2})); + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeRetireConnectionIdPacket( + packet_num++, false, 0u)); } else { // Ping packet to send after migration is completed. quic_data2.AddWrite( @@ -6024,6 +6241,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -6392,6 +6610,13 @@ // Set up the second socket data provider that is used for probing. MockQuicData quic_data1(version_); + quic::QuicConnectionId cid_on_old_path = + quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } // Connectivity probe to be sent on the new path. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_num++, true)); @@ -6422,8 +6647,15 @@ // Ping packet to send after migration is completed. quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, false)); - + if (VersionUsesHttp3(version_.transport_version)) { + quic_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket(packet_num++, false, 0u)); + } } else { + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_old_path); + } if (version_.UsesTls()) { if (VersionUsesHttp3(version_.transport_version)) { socket_data.AddWrite( @@ -6497,6 +6729,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Trigger connection migration. Since there is a non-migratable stream, // this should cause session to migrate. @@ -6630,12 +6863,15 @@ // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + } if (version_.UsesHttp3()) { + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true); spdy::Http2HeaderBlock headers = client_maker_.GetRequestHeaders("GET", "https", "/"); spdy::SpdyPriority priority = @@ -6648,9 +6884,21 @@ true, true, priority, std::move(headers), GetNthClientInitiatedBidirectionalStreamId(0), &spdy_headers_frame_len)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); } else { socket_data1.AddWrite( SYNCHRONOUS, + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true)); + socket_data1.AddWrite( + SYNCHRONOUS, ConstructGetRequestPacket( packet_num++, GetNthClientInitiatedBidirectionalStreamId(1), GetNthClientInitiatedBidirectionalStreamId(0), true, true)); @@ -6743,6 +6991,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(2u, session->GetNumActiveStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream1. This should cause an async write error. HttpResponseInfo response; @@ -6766,6 +7015,8 @@ // Run the task runner so that migration on write error is finally executed. task_runner->RunUntilIdle(); + // Fire the retire connection ID alarm. + base::RunLoop().RunUntilIdle(); // Verify the session is still alive and not marked as going away. EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -6814,6 +7065,7 @@ MockQuicData socket_data(version_); socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); int packet_num = 1; + int peer_packet_num = 1; if (VersionUsesHttp3(version_.transport_version)) { socket_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(packet_num++)); @@ -6825,20 +7077,44 @@ // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData quic_data2(version_); - quic_data2.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); - if (version_.UsesHttp3()) { + quic::QuicConnectionId cid1 = quic::test::TestConnectionId(12345678); + quic::QuicConnectionId cid2 = quic::test::TestConnectionId(87654321); + if (!version_.UsesHttp3()) { + quic_data2.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, + /*fin=*/true)); + } else { + client_maker_.set_connection_id(cid1); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, + /*fin=*/true); quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, true)); + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + quic_data2.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + quic_data2.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + quic_data2.AddRead(ASYNC, server_maker_.MakeAckAndNewConnectionIdPacket( + peer_packet_num++, false, packet_num - 1, 1u, + cid2, /*sequence_number=*/2u, + /*retire_prior_to=*/1u)); } quic_data2.AddRead( - ASYNC, - ConstructOkResponsePacket( - 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); + ASYNC, ConstructOkResponsePacket( + peer_packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), false, false)); quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); quic_data2.AddSocketDataToFactory(socket_factory_.get()); @@ -6869,6 +7145,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(1u, session->GetNumActiveStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid1, session); // Send GET request. This should cause an async write error. HttpResponseInfo response; @@ -6885,6 +7162,8 @@ // Run the task runner so that migration on write error is finally executed. task_runner->RunUntilIdle(); + // Make sure the alarm that retires connection ID on the old path is fired. + base::RunLoop().RunUntilIdle(); // Verify the session is still alive and not marked as going away. EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -6904,18 +7183,23 @@ // Set up the third socket data provider for migrate back to default network. MockQuicData quic_data3(version_); + if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid2); + } // Connectivity probe to be sent on the new path. quic_data3.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( packet_num++, false)); // Connectivity probe to receive from the server. - quic_data3.AddRead(ASYNC, - server_maker_.MakeConnectivityProbingPacket(2, false)); + quic_data3.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket( + peer_packet_num++, /*include_version=*/false)); quic_data3.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (version_.UsesHttp3()) { - // Data sent to the old address was in-flight and thus will be - // retransmistted. - quic_data3.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( - packet_num++, 1, 2, 1, {1, 2})); + // There is no other data to retransmit as they have been acknowledged by + // the packet containing NEW_CONNECTION_ID frame from the server. + quic_data3.AddWrite(ASYNC, client_maker_.MakeAckPacket( + packet_num++, /*first_received=*/1, + /*largest_received=*/peer_packet_num - 1, + /*smallest_received=*/1)); } else { quic_data3.AddWrite(ASYNC, client_maker_.MakeAckPacket(packet_num++, 1, 2, 1)); @@ -7147,8 +7431,9 @@ socket_data2.AddRead(ASYNC, ERR_IO_PENDING); // Pause. // Change the encryption level after handshake is confirmed. client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - if (VersionUsesHttp3(version_.transport_version)) + if (VersionUsesHttp3(version_.transport_version)) { socket_data2.AddWrite(ASYNC, ConstructInitialSettingsPacket(packet_num++)); + } socket_data2.AddWrite( ASYNC, ConstructGetRequestPacket( packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), @@ -7158,14 +7443,19 @@ ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); - int probing_packet_num = packet_num++; - if (VersionUsesHttp3(version_.transport_version)) { - socket_data2.AddWrite( - SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( - packet_num++, false, GetQpackDecoderStreamId(), 1, 1, - false, StreamCancellationQpackDecoderInstruction(0))); + socket_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*largest_received=*/1u, + /*smallest_received=*/1u, + /*sequence_number=*/1u)); + socket_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeDataPacket( + packet_num++, GetQpackDecoderStreamId(), + /*should_include_version=*/false, /*fin=*/false, + StreamCancellationQpackDecoderInstruction(0))); socket_data2.AddWrite( SYNCHRONOUS, client_maker_.MakeRstPacket( @@ -7182,6 +7472,10 @@ // Socket data for probing on the default network. MockQuicData probing_data(version_); + quic::QuicConnectionId cid_on_path1 = quic::test::TestConnectionId(1234567); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_path1); + } probing_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. probing_data.AddWrite( SYNCHRONOUS, @@ -7233,6 +7527,7 @@ ->NotifySessionOneRttKeyAvailable(); EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_path1, session2); // Resume the data now so that data can be sent and read. socket_data2.Resume(); @@ -7521,24 +7816,46 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, + /*fin=*/true); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeCombinedRetransmissionPacket( + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + socket_data1.AddWrite(ASYNC, client_maker_.MakePingPacket( + packet_num++, /*include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (VersionUsesHttp3(version_.transport_version)) { - socket_data1.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, false)); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( packet_num++, false, GetQpackDecoderStreamId(), 1, 1, @@ -7568,7 +7885,7 @@ // data queued in the new socket is read by the packet reader. base::RunLoop().RunUntilIdle(); - // Verify that session is alive and not marked as going awya. + // Verify that session is alive and not marked as going away. EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(1u, session->GetNumActiveStreams()); @@ -7730,19 +8047,42 @@ // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, + /*fin=*/true); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeCombinedRetransmissionPacket( + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, + /*include_version=*/false)); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, + /*fin=*/true)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (VersionUsesHttp3(version_.transport_version)) { - socket_data1.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, false)); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( packet_num++, false, GetQpackDecoderStreamId(), 1, 1, @@ -7823,6 +8163,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(2u, session->GetNumActiveStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. This should cause a write error, which triggers // a connection migration attempt. @@ -7892,19 +8233,38 @@ // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_number++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(1234567); if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, + /*fin=*/true); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeRetransmissionRstAndDataPacket( - {1, 2}, packet_number++, true, + /*original_packet_numbers=*/{1, 2}, packet_number++, + /*include_version=*/false, GetNthClientInitiatedBidirectionalStreamId(1), quic::QUIC_STREAM_CANCELLED, GetQpackDecoderStreamId(), StreamCancellationQpackDecoderInstruction(1))); + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_number++, + /*include_version=*/false)); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, + /*sequence_number=*/0u)); } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, + /*fin=*/true)); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRstPacket( packet_number++, true, @@ -7987,6 +8347,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(2u, session->GetNumActiveStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream 1. This should cause a write error, which // triggers a connection migration attempt. @@ -8053,25 +8414,44 @@ ERR_ADDRESS_UNREACHABLE); // Write error. socket_data.AddSocketDataToFactory(socket_factory_.get()); - // Set up second socket data provider that is used after - // migration. The request is rewritten to this new socket, and the - // response to the request is read on this new socket. + // Set up second socket data provider that is used after migration. The + // request is rewritten to this new socket, and the response to the request is + // read on this new socket. MockQuicData socket_data1(version_); - // The packet triggered writer error will be sent anyway even if the stream - // will be cancelled later. - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_number++, - GetNthClientInitiatedBidirectionalStreamId(1), - true, true)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(1), + /*should_include_version=*/false, + /*fin=*/true); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeRetransmissionRstAndDataPacket( - {1}, packet_number++, true, + /*original_packet_numbers=*/{1}, packet_number++, + /*include_version=*/false, GetNthClientInitiatedBidirectionalStreamId(1), quic::QUIC_STREAM_CANCELLED, GetQpackDecoderStreamId(), StreamCancellationQpackDecoderInstruction(1))); + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_number++, + /*include_version=*/false)); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_number++, /*include_version=*/false, + /*sequence_number=*/0u)); } else { + // The packet triggered writer error will be sent anyway even if the stream + // will be cancelled later. + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(1), + /*should_include_version=*/true, + /*fin=*/true)); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRstPacket( packet_number++, true, @@ -8159,6 +8539,7 @@ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(2u, session->GetNumActiveStreams()); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream 2 which is non-migratable. This should cause a // write error, which triggers a connection migration attempt. @@ -8214,6 +8595,8 @@ MockQuicData failed_socket_data(version_); MockQuicData socket_data(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); int packet_num = 1; if (migrate_idle_sessions) { // The socket data provider for the original socket before migration. @@ -8227,24 +8610,42 @@ // Set up second socket data provider that is used after migration. socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. - // Although the write error occurs when writing a packet for the - // non-migratable stream and the stream will be cancelled during migration, - // the packet will still be retransimitted at the connection level. - socket_data.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); - // A RESET will be sent to the peer to cancel the non-migratable stream. if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, + /*fin=*/true); socket_data.AddWrite( SYNCHRONOUS, client_maker_.MakeRetransmissionRstAndDataPacket( - {1}, packet_num++, true, + /*original_packet_numbers=*/{1}, packet_num++, + /*include_version=*/false, GetNthClientInitiatedBidirectionalStreamId(0), quic::QUIC_STREAM_CANCELLED, GetQpackDecoderStreamId(), StreamCancellationQpackDecoderInstruction(0))); + socket_data.AddWrite( + SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, + /*include_version=*/false)); + socket_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); } else { + // Although the write error occurs when writing a packet for the + // non-migratable stream and the stream will be cancelled during + // migration, the packet will still be retransimitted at the connection + // level. + socket_data.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, + /*fin=*/true)); + // A RESET will be sent to the peer to cancel the non-migratable stream. socket_data.AddWrite( SYNCHRONOUS, client_maker_.MakeRstPacket( @@ -8287,6 +8688,7 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. This should cause a write error, which triggers // a connection migration attempt. @@ -8406,9 +8808,21 @@ TestMigrationOnWriteErrorMigrationDisabled(ASYNC); } -// Sets up a test which verifies that connection migration on write error can -// eventually succeed and rewrite the packet on the new network with singals -// delivered in the following order (alternate network is always availabe): +// For IETF QUIC, this test the following scenario: +// - original network encounters a SYNC/ASYNC write error based on +// |write_error_mode_on_old_network|, the packet failed to be written is +// cached, session migrates immediately to the alternate network. +// - an immediate SYNC/ASYNC write error based on +// |write_error_mode_on_new_network| is encountered after migration to the +// alternate network, session migrates immediately to the original network. +// - After a new socket for the original network is created and starts to read, +// connection migration fails due to lack of unused connection ID and +// connection is closed. +// +// For gQUIC, sets up a test which verifies that connection migration on write +// error can eventually succeed and rewrite the packet on the new network with +// signals delivered in the following order (alternate network is always +// available): // - original network encounters a SYNC/ASYNC write error based on // |write_error_mode_on_old_network|, the packet failed to be written is // cached, session migrates immediately to the alternate network. @@ -8446,54 +8860,47 @@ ERR_ADDRESS_UNREACHABLE); // Write Error socket_data1.AddSocketDataToFactory(socket_factory_.get()); - // Set up the socket data used by the alternate network, which also - // encounters a write error. + // Set up the socket data used by the alternate network, which + // - is not used to write as migration fails due to lack of connection ID. + // - encounters a write error in gQUIC. MockQuicData failed_quic_data2(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); failed_quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); failed_quic_data2.AddWrite(write_error_mode_on_new_network, ERR_FAILED); failed_quic_data2.AddSocketDataToFactory(socket_factory_.get()); - // Set up the third socket data used by original network, which encounters a - // write error again. + // Set up the third socket data used by original network, which + // - encounters a write error again. MockQuicData failed_quic_data1(version_); failed_quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); - failed_quic_data1.AddWrite(write_error_mode_on_old_network, ERR_FAILED); + if (!VersionUsesHttp3(version_.transport_version)) { + failed_quic_data1.AddWrite(write_error_mode_on_old_network, ERR_FAILED); + } failed_quic_data1.AddSocketDataToFactory(socket_factory_.get()); - // Set up the last socket data used by the alternate network, which will - // finish migration successfully. The request is rewritten to this new socket, - // and the response to the request is read on this socket. MockQuicData socket_data2(version_); - socket_data2.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); - socket_data2.AddRead( - ASYNC, - ConstructOkResponsePacket( - 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); - socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); - if (VersionUsesHttp3(version_.transport_version)) { - socket_data2.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, false)); - socket_data2.AddWrite( - SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( - packet_num++, false, GetQpackDecoderStreamId(), 1, 1, - false, StreamCancellationQpackDecoderInstruction(0))); + if (!VersionUsesHttp3(version_.transport_version)) { + // Set up the last socket data used by the alternate network, which will + // finish migration successfully. The request is rewritten to this new + // socket, and the response to the request is read on this socket. socket_data2.AddWrite( SYNCHRONOUS, - client_maker_.MakeRstPacket( - packet_num++, false, GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); - } else { + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true)); + socket_data2.AddRead( + ASYNC, + ConstructOkResponsePacket( + 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); + socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); socket_data2.AddWrite( SYNCHRONOUS, client_maker_.MakeAckAndRstPacket( packet_num++, false, GetNthClientInitiatedBidirectionalStreamId(0), quic::QUIC_STREAM_CANCELLED, 1, 1)); + socket_data2.AddSocketDataToFactory(socket_factory_.get()); } - socket_data2.AddSocketDataToFactory(socket_factory_.get()); // Create request and QuicHttpStream. QuicStreamRequest request(factory_.get()); @@ -8521,35 +8928,42 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. // This should encounter a write error on network 1, // then migrate to network 2, which encounters another write error, // and migrate again to network 1, which encoutners one more write error. - // Finally the session migrates to network 2 successfully. HttpResponseInfo response; HttpRequestHeaders request_headers; EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); - EXPECT_EQ(1u, session->GetNumActiveStreams()); + if (VersionUsesHttp3(version_.transport_version)) { + // Connection is closed as there is no connection ID available yet for the + // second migration. + EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + stream.reset(); + } else { + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); - // Verify that response headers on the migrated socket were delivered to the - // stream. - EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); - EXPECT_EQ(200, response.headers->response_code()); + // Verify that response headers on the migrated socket were delivered to the + // stream. + EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); + EXPECT_EQ(200, response.headers->response_code()); - stream.reset(); + stream.reset(); + EXPECT_TRUE(socket_data2.AllReadDataConsumed()); + EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); + } EXPECT_TRUE(socket_data1.AllReadDataConsumed()); EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); EXPECT_TRUE(failed_quic_data2.AllReadDataConsumed()); EXPECT_TRUE(failed_quic_data2.AllWriteDataConsumed()); EXPECT_TRUE(failed_quic_data1.AllReadDataConsumed()); EXPECT_TRUE(failed_quic_data1.AllWriteDataConsumed()); - EXPECT_TRUE(socket_data2.AllReadDataConsumed()); - EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); } TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncSync) { @@ -8660,20 +9074,39 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, /*fin=*/true); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, true)); + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true)); } socket_data1.AddRead( ASYNC, @@ -8817,20 +9250,39 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); - if (version_.UsesHttp3()) { + if (!version_.UsesHttp3()) { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true)); + } else { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, /*fin=*/true); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, true)); + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); } socket_data1.AddRead( ASYNC, @@ -8980,6 +9432,9 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. HttpResponseInfo response; @@ -8996,23 +9451,43 @@ // Set up second socket data provider that is used after migration. // The response to the earlier request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, /*fin=*/true); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (VersionUsesHttp3(version_.transport_version)) { - socket_data1.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, false)); socket_data1.AddWrite( - SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( - packet_num++, false, GetQpackDecoderStreamId(), 1, 1, - false, StreamCancellationQpackDecoderInstruction(0))); + SYNCHRONOUS, + client_maker_.MakeAckRetransmissionAndRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*largest_received=*/1, + /*smallest_received=*/1, /*original_packet_numbers=*/{1, 2}, + /*sequence_number=*/0u)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeDataPacket( + packet_num++, GetQpackDecoderStreamId(), + /*should_include_version=*/false, + /*fin=*/false, StreamCancellationQpackDecoderInstruction(0))); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeRstPacket( @@ -9135,18 +9610,26 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The response to the request is read on this new socket. MockQuicData socket_data1(version_); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeCombinedRetransmissionPacket( {1, 2}, packet_num++, true)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - socket_data1.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( @@ -9262,23 +9745,37 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is written to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( 1, packet_num++, true)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } socket_data1.AddWrite( SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); - socket_data1.AddWrite( - SYNCHRONOUS, ConstructGetRequestPacket(packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), true, true)); + if (VersionUsesHttp3(version_.transport_version)) { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/true, /*sequence_number=*/0u)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( @@ -9399,23 +9896,37 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is written to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( 1, packet_num++, true)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } socket_data1.AddWrite( SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); - socket_data1.AddWrite( - SYNCHRONOUS, ConstructGetRequestPacket(packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), true, true)); + if (version_.UsesHttp3()) { + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( @@ -9516,14 +10027,22 @@ // migration. The request is written to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( 1, packet_num++, true)); } // The PING packet sent post migration. socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, true)); + if (version_.UsesHttp3()) { + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + } socket_data1.AddWrite( SYNCHRONOUS, ConstructGetRequestPacket(packet_num++, @@ -9592,6 +10111,7 @@ // Ensure that session is alive and active. QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Now notify network is disconnected, cause the migration to complete // immediately. @@ -9684,13 +10204,22 @@ // migration. The request is written to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid_on_new_path); socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( 1, packet_num++, true)); } // The PING packet sent post migration. socket_data1.AddWrite(SYNCHRONOUS, client_maker_.MakePingPacket(packet_num++, true)); + if (version_.UsesHttp3()) { + socket_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, + /*sequence_number=*/0u)); + } socket_data1.AddWrite( SYNCHRONOUS, ConstructGetRequestPacket(packet_num++, @@ -9758,6 +10287,7 @@ // Ensure that session is alive and active. QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Now notify network is disconnected, cause the migration to complete // immediately. @@ -10433,19 +10963,29 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Set up second socket data provider that is used after // migration. The request is written to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); if (version_.UsesHttp3()) { - socket_data1.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, true)); + client_maker_.set_connection_id(cid_on_new_path); + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true); + socket_data1.AddWrite(ASYNC, + client_maker_.MakeCombinedRetransmissionPacket( + /*original_packet_numbers=*/{1, 2}, packet_num++, + /*should_include_version=*/false)); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true)); } socket_data1.AddRead( ASYNC, @@ -10527,7 +11067,7 @@ SYNCHRONOUS, /*disconnect_before_connect*/ true); } -// Setps up test which verifies that session successfully migrate to alternate +// Sets up test which verifies that session successfully migrate to alternate // network with signals delivered in the following order: // *NOTE* Signal (A) and (B) can reverse order based on // |disconnect_before_connect|. @@ -10587,6 +11127,9 @@ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + quic::QuicConnectionId cid_on_new_path = + quic::test::TestConnectionId(12345678); + MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session); // Send GET request on stream. This should cause a write error, which triggers // a connection migration attempt. @@ -10609,23 +11152,42 @@ // migration. The request is rewritten to this new socket, and the // response to the request is read on this new socket. MockQuicData socket_data1(version_); - socket_data1.AddWrite( - SYNCHRONOUS, - ConstructGetRequestPacket(packet_num++, - GetNthClientInitiatedBidirectionalStreamId(0), - true, true)); + if (VersionUsesHttp3(version_.transport_version)) { + client_maker_.set_connection_id(cid_on_new_path); + // Increment packet number to account for packet write error on the old + // path. Also save the packet in client_maker_ for constructing the + // retransmission packet. + ConstructGetRequestPacket(packet_num++, + GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/false, /*fin=*/true); + } else { + socket_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket( + packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), + /*should_include_version=*/true, /*fin=*/true)); + } socket_data1.AddRead( ASYNC, ConstructOkResponsePacket( 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false)); socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); if (VersionUsesHttp3(version_.transport_version)) { - socket_data1.AddWrite(ASYNC, client_maker_.MakeCombinedRetransmissionPacket( - {1, 2}, packet_num++, false)); + socket_data1.AddWrite(ASYNC, client_maker_.MakeAckAndRetransmissionPacket( + packet_num++, /*first_received=*/1, + /*largest_received=*/1, + /*smallest_received=*/1, + /*original_packet_numbers=*/{1, 2})); socket_data1.AddWrite( - SYNCHRONOUS, client_maker_.MakeAckAndDataPacket( - packet_num++, false, GetQpackDecoderStreamId(), 1, 1, - false, StreamCancellationQpackDecoderInstruction(0))); + SYNCHRONOUS, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeDataPacket( + packet_num++, GetQpackDecoderStreamId(), + /*should_include_version=*/false, + /*fin=*/false, StreamCancellationQpackDecoderInstruction(0))); socket_data1.AddWrite( SYNCHRONOUS, client_maker_.MakeRstPacket( @@ -10715,7 +11277,23 @@ QuicStreamFactoryPeer::SetTickClock(factory_.get(), task_runner->GetMockTickClock()); + quic::QuicConnectionId cid1 = quic::test::TestConnectionId(1234567); + quic::QuicConnectionId cid2 = quic::test::TestConnectionId(2345671); + quic::QuicConnectionId cid3 = quic::test::TestConnectionId(3456712); + quic::QuicConnectionId cid4 = quic::test::TestConnectionId(4567123); + quic::QuicConnectionId cid5 = quic::test::TestConnectionId(5671234); + quic::QuicConnectionId cid6 = quic::test::TestConnectionId(6712345); + quic::QuicConnectionId cid7 = quic::test::TestConnectionId(7123456); + + int peer_packet_num = 1; MockQuicData default_socket_data(version_); + if (version_.UsesHttp3()) { + default_socket_data.AddRead( + SYNCHRONOUS, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid1, + /*sequence_number=*/1u, + /*retire_prior_to=*/0u)); + } default_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); int packet_num = 1; if (VersionUsesHttp3(version_.transport_version)) { @@ -10726,16 +11304,88 @@ // Set up second socket data provider that is used after migration. MockQuicData alternate_socket_data(version_); - alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid1); + alternate_socket_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( + /*original_packet_number=*/1, packet_num++, + /*should_include_version=*/false)); alternate_socket_data.AddWrite( SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, packet_num++, true)); + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid2, + /*sequence_number=*/2u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/2u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid3, + /*sequence_number=*/3u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/3u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid4, + /*sequence_number=*/4u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/4u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid5, + /*sequence_number=*/5u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/5u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid6, + /*sequence_number=*/6u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, 6u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid7, + /*sequence_number=*/7u, + /*retire_prior_to=*/1u)); + alternate_socket_data.AddRead(SYNCHRONOUS, + ERR_IO_PENDING); // Hanging read. + } else { + alternate_socket_data.AddRead(SYNCHRONOUS, + ERR_IO_PENDING); // Hanging read. + // Ping packet to send after migration. + alternate_socket_data.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - // Ping packet to send after migration. - alternate_socket_data.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); // Set up probing socket for migrating back to the default network. @@ -10815,6 +11465,12 @@ // Retry migrate back in 1, 2, 4, 8, 16s. // Session will be closed due to idle migration timeout. for (int i = 0; i < 5; i++) { + if (version_.UsesHttp3()) { + // Fire retire connection ID alarm. + base::RunLoop().RunUntilIdle(); + // Make new connection ID available. + alternate_socket_data.Resume(); + } EXPECT_TRUE(HasActiveSession(host_port_pair_)); // A task is posted to migrate back to the default network in 2^i seconds. EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); @@ -10846,7 +11502,22 @@ QuicStreamFactoryPeer::SetTickClock(factory_.get(), task_runner->GetMockTickClock()); + quic::QuicConnectionId cid1 = quic::test::TestConnectionId(1234567); + quic::QuicConnectionId cid2 = quic::test::TestConnectionId(2345671); + quic::QuicConnectionId cid3 = quic::test::TestConnectionId(3456712); + quic::QuicConnectionId cid4 = quic::test::TestConnectionId(4567123); + quic::QuicConnectionId cid5 = quic::test::TestConnectionId(5671234); + quic::QuicConnectionId cid6 = quic::test::TestConnectionId(6712345); + + int peer_packet_num = 1; MockQuicData default_socket_data(version_); + if (version_.UsesHttp3()) { + default_socket_data.AddRead( + SYNCHRONOUS, + server_maker_.MakeNewConnectionIdPacket(peer_packet_num++, true, cid1, + /*sequence_number=*/1u, + /*retire_prior_to=*/0u)); + } default_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); int packet_num = 1; if (VersionUsesHttp3(version_.transport_version)) { @@ -10857,16 +11528,67 @@ // Set up second socket data provider that is used after migration. MockQuicData alternate_socket_data(version_); - alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. if (version_.UsesHttp3()) { + client_maker_.set_connection_id(cid1); + alternate_socket_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRetransmissionPacket( + /*original_packet_number=*/1u, packet_num++, + /*should_include_version=*/false)); alternate_socket_data.AddWrite( SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, packet_num++, true)); + client_maker_.MakePingPacket(packet_num++, /*include_version=*/false)); + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/0u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid2, + /*sequence_number=*/2u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/2u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid3, + /*sequence_number=*/3u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/3u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid4, + /*sequence_number=*/4u, + /*retire_prior_to=*/1u)); + ++packet_num; // Probing packet on default network encounters write error. + alternate_socket_data.AddWrite( + ASYNC, + client_maker_.MakeRetireConnectionIdPacket( + packet_num++, /*include_version=*/false, /*sequence_number=*/4u)); + alternate_socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause. + alternate_socket_data.AddRead( + ASYNC, server_maker_.MakeNewConnectionIdPacket( + peer_packet_num++, /*include_version=*/false, cid5, + /*sequence_number=*/5u, + /*retire_prior_to=*/1u)); + alternate_socket_data.AddRead(SYNCHRONOUS, + ERR_IO_PENDING); // Hanging read. + } else { + alternate_socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read + // Ping packet to send after migration. + alternate_socket_data.AddWrite( + SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); } - // Ping packet to send after migration. - alternate_socket_data.AddWrite( - SYNCHRONOUS, - client_maker_.MakePingPacket(packet_num++, /*include_version=*/true)); alternate_socket_data.AddSocketDataToFactory(socket_factory_.get()); // Set up probing socket for migrating back to the default network. @@ -10941,6 +11663,12 @@ // Retry migrate back in 1, 2, 4, 8s. // Session will be closed due to idle migration timeout. for (int i = 0; i < 4; i++) { + if (version_.UsesHttp3()) { + // Fire retire connection ID alarm. + base::RunLoop().RunUntilIdle(); + // Make new connection ID available. + alternate_socket_data.Resume(); + } EXPECT_TRUE(HasActiveSession(host_port_pair_)); // A task is posted to migrate back to the default network in 2^i seconds. EXPECT_EQ(1u, task_runner->GetPendingTaskCount());
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc index f2e7b4a17..7d1c223 100644 --- a/net/quic/quic_test_packet_maker.cc +++ b/net/quic/quic_test_packet_maker.cc
@@ -171,6 +171,46 @@ } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeRetireConnectionIdPacket(uint64_t num, + bool include_version, + uint64_t sequence_number) { + InitializeHeader(num, include_version); + AddQuicRetireConnectionIdFrame(sequence_number); + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeNewConnectionIdPacket( + uint64_t num, + bool include_version, + const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to) { + InitializeHeader(num, include_version); + AddQuicNewConnectionIdFrame( + cid, sequence_number, retire_prior_to, + quic::QuicUtils::GenerateStatelessResetToken(cid)); + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeAckAndNewConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to) { + InitializeHeader(num, include_version); + AddQuicAckFrame(largest_received, smallest_received); + AddQuicNewConnectionIdFrame( + cid, sequence_number, retire_prior_to, + quic::QuicUtils::GenerateStatelessResetToken(cid)); + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeDummyCHLOPacket(uint64_t packet_num) { SetEncryptionLevel(quic::ENCRYPTION_INITIAL); InitializeHeader(packet_num, /*include_version=*/true); @@ -207,6 +247,38 @@ } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeAckAndRetireConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + uint64_t sequence_number) { + InitializeHeader(num, include_version); + AddQuicAckFrame(largest_received, smallest_received); + AddQuicRetireConnectionIdFrame(sequence_number); + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeAckRetransmissionAndRetireConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + const std::vector<uint64_t>& original_packet_numbers, + uint64_t sequence_number) { + InitializeHeader(num, include_version); + AddQuicAckFrame(largest_received, smallest_received); + for (auto it : original_packet_numbers) { + for (auto frame : saved_frames_[quic::QuicPacketNumber(it)]) { + frames_.push_back(frame); + } + } + AddQuicRetireConnectionIdFrame(sequence_number); + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeStreamsBlockedPacket( uint64_t num, bool include_version, @@ -698,6 +770,29 @@ } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeAckRetransmissionAndDataPacket( + uint64_t packet_number, + bool include_version, + const std::vector<uint64_t>& original_packet_numbers, + quic::QuicStreamId stream_id, + uint64_t largest_received, + uint64_t smallest_received, + bool fin, + absl::string_view data) { + InitializeHeader(packet_number, include_version); + + AddQuicAckFrame(largest_received, smallest_received); + for (auto it : original_packet_numbers) { + for (auto frame : saved_frames_[quic::QuicPacketNumber(it)]) { + frames_.push_back(frame); + } + } + AddQuicStreamFrame(stream_id, fin, data); + + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket( uint64_t packet_number, quic::QuicStreamId stream_id, @@ -1263,6 +1358,28 @@ DVLOG(1) << "Adding frame: " << frames_.back(); } +void QuicTestPacketMaker::AddQuicRetireConnectionIdFrame( + uint64_t sequence_number) { + auto* retire_cid_frame = new quic::QuicRetireConnectionIdFrame(); + retire_cid_frame->sequence_number = sequence_number; + frames_.push_back(quic::QuicFrame(retire_cid_frame)); + DVLOG(1) << "Adding frame: " << frames_.back(); +} + +void QuicTestPacketMaker::AddQuicNewConnectionIdFrame( + const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to, + quic::StatelessResetToken reset_token) { + auto* new_cid_frame = new quic::QuicNewConnectionIdFrame(); + new_cid_frame->connection_id = cid; + new_cid_frame->sequence_number = sequence_number; + new_cid_frame->retire_prior_to = retire_prior_to; + new_cid_frame->stateless_reset_token = reset_token; + frames_.push_back(quic::QuicFrame(new_cid_frame)); + DVLOG(1) << "Adding frame: " << frames_.back(); +} + void QuicTestPacketMaker::AddQuicMaxStreamsFrame( quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count,
diff --git a/net/quic/quic_test_packet_maker.h b/net/quic/quic_test_packet_maker.h index 89b28837..1aad75e 100644 --- a/net/quic/quic_test_packet_maker.h +++ b/net/quic/quic_test_packet_maker.h
@@ -8,6 +8,7 @@ #define NET_QUIC_QUIC_TEST_PACKET_MAKER_H_ #include <stddef.h> +#include <sys/types.h> #include <memory> #include <string> @@ -55,6 +56,10 @@ void set_hostname(const std::string& host); + void set_connection_id(const quic::QuicConnectionId& connection_id) { + connection_id_ = connection_id; + } + std::unique_ptr<quic::QuicReceivedPacket> MakeConnectivityProbingPacket( uint64_t num, bool include_version); @@ -63,6 +68,27 @@ uint64_t num, bool include_version); + std::unique_ptr<quic::QuicReceivedPacket> MakeRetireConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t sequence_number); + + std::unique_ptr<quic::QuicReceivedPacket> MakeNewConnectionIdPacket( + uint64_t num, + bool include_version, + const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to); + + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndNewConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to); + std::unique_ptr<quic::QuicReceivedPacket> MakeDummyCHLOPacket( uint64_t packet_num); @@ -72,6 +98,22 @@ uint64_t largest_received, uint64_t smallest_received); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndRetireConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + uint64_t sequence_number); + + std::unique_ptr<quic::QuicReceivedPacket> + MakeAckRetransmissionAndRetireConnectionIdPacket( + uint64_t num, + bool include_version, + uint64_t largest_received, + uint64_t smallest_received, + const std::vector<uint64_t>& original_packet_numbers, + uint64_t sequence_number); + std::unique_ptr<quic::QuicReceivedPacket> MakeStreamsBlockedPacket( uint64_t num, bool include_version, @@ -290,6 +332,16 @@ bool fin, absl::string_view data); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckRetransmissionAndDataPacket( + uint64_t packet_number, + bool include_version, + const std::vector<uint64_t>& original_packet_numbers, + quic::QuicStreamId stream_id, + uint64_t largest_received, + uint64_t smallest_received, + bool fin, + absl::string_view data); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndRetransmissionPacket( uint64_t packet_number, uint64_t first_received, @@ -460,6 +512,11 @@ // Add frames to current packet. void AddQuicPaddingFrame(); void AddQuicPingFrame(); + void AddQuicRetireConnectionIdFrame(uint64_t sequence_number); + void AddQuicNewConnectionIdFrame(const quic::QuicConnectionId& cid, + uint64_t sequence_number, + uint64_t retire_prior_to, + quic::StatelessResetToken reset_token); void AddQuicMaxStreamsFrame(quic::QuicControlFrameId control_frame_id, quic::QuicStreamCount stream_count, bool unidirectional);
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 7f60bae..245e123 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc
@@ -304,7 +304,8 @@ return MockWriteResult(SYNCHRONOUS, data.length()); } EXPECT_FALSE(helper_.AllWriteDataConsumed()) - << "No more mock data to match write:\n" + << "No more mock data to match write:\nFormatted write data:\n" + << printer_->PrintWrite(data) << "Raw write data:\n" << HexDump(data); if (helper_.AllWriteDataConsumed()) { return MockWriteResult(SYNCHRONOUS, ERR_UNEXPECTED); @@ -496,7 +497,8 @@ MockWriteResult SequencedSocketData::OnWrite(const std::string& data) { CHECK_EQ(IDLE, write_state_); CHECK(!helper_.AllWriteDataConsumed()) - << "\nNo more mock data to match write:\n" + << "\nNo more mock data to match write:\nFormatted write data:\n" + << printer_->PrintWrite(data) << "Raw write data:\n" << HexDump(data); NET_TRACE(1, " *** ") << "sequence_number: " << sequence_number_;
diff --git a/printing/backend/mojom/print_backend.mojom b/printing/backend/mojom/print_backend.mojom index 508e8778..c035efe 100644 --- a/printing/backend/mojom/print_backend.mojom +++ b/printing/backend/mojom/print_backend.mojom
@@ -66,7 +66,7 @@ array<Paper> papers; array<Paper> user_defined_papers; Paper default_paper; - array<gfx.mojom.Size> dpis; + array<gfx.mojom.Size> dpis; // Duplicates allowed. gfx.mojom.Size default_dpi; [EnableIf=is_chromeos]
diff --git a/printing/backend/mojom/print_backend_mojom_traits.cc b/printing/backend/mojom/print_backend_mojom_traits.cc index 52ca698..8ef4e9a 100644 --- a/printing/backend/mojom/print_backend_mojom_traits.cc +++ b/printing/backend/mojom/print_backend_mojom_traits.cc
@@ -242,12 +242,6 @@ return false; } - DuplicateChecker<gfx::Size> dpis_dup_checker; - if (dpis_dup_checker.HasDuplicates(out->dpis)) { - DLOG(ERROR) << "Duplicate dpis detected."; - return false; - } - #if defined(OS_CHROMEOS) DuplicateChecker<printing::AdvancedCapability> advanced_capabilities_dup_checker;
diff --git a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc index ad48784..b4f2fe8 100644 --- a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc +++ b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc
@@ -312,12 +312,6 @@ EXPECT_FALSE(mojo::test::SerializeAndDeserialize< mojom::PrinterSemanticCapsAndDefaults>(input, output)); - input = GenerateSamplePrinterSemanticCapsAndDefaults(); - input.dpis = {kDpi600, kDpi600, kDpi1200}; - - EXPECT_FALSE(mojo::test::SerializeAndDeserialize< - mojom::PrinterSemanticCapsAndDefaults>(input, output)); - #if defined(OS_CHROMEOS) // Use an advanced capability with same name but different other fields. AdvancedCapability advanced_capability1_prime = kAdvancedCapability1; @@ -332,4 +326,22 @@ #endif } +TEST( + PrintBackendMojomTraitsTest, + TestSerializeAndDeserializePrinterSemanticCapsAndDefaultsAllowedDuplicatesInArrays) { + PrinterSemanticCapsAndDefaults input = + GenerateSamplePrinterSemanticCapsAndDefaults(); + PrinterSemanticCapsAndDefaults output; + + // Override sample with arrays containing duplicates where it is allowed. + // Duplicate DPIs are known to be possible, seen with the Kyocera KX driver. + const std::vector<gfx::Size> kDuplicateDpis{kDpi600, kDpi600, kDpi1200}; + input.dpis = kDuplicateDpis; + + EXPECT_TRUE(mojo::test::SerializeAndDeserialize< + mojom::PrinterSemanticCapsAndDefaults>(input, output)); + + EXPECT_EQ(kDuplicateDpis, output.dpis); +} + } // namespace printing
diff --git a/remoting/host/chromeos/BUILD.gn b/remoting/host/chromeos/BUILD.gn index f12d3ac..74d2ae5 100644 --- a/remoting/host/chromeos/BUILD.gn +++ b/remoting/host/chromeos/BUILD.gn
@@ -44,6 +44,28 @@ ] } +source_set("remoting_service") { + sources = [ + "remote_support_host_ash.cc", + "remote_support_host_ash.h", + "remoting_service.cc", + "remoting_service.h", + ] + + public_deps = [ "//remoting/host/it2me:chrome_os_host" ] + + configs += [ "//remoting/build/config:version" ] + + deps = [ + "//chrome/browser:browser_process", + "//content/public/browser:browser", + "//mojo/public/cpp/bindings", + "//remoting/base:base", + "//remoting/host", + "//remoting/host/mojom:mojom", + ] +} + # The host portions of the remoting unit tests. source_set("unit_tests") { testonly = true
diff --git a/remoting/host/chromeos/DEPS b/remoting/host/chromeos/DEPS new file mode 100644 index 0000000..ca7508a --- /dev/null +++ b/remoting/host/chromeos/DEPS
@@ -0,0 +1,8 @@ +specific_include_rules = { + "remoting_service.cc": [ + "+chrome/browser/browser_process.h", + "+content/public/browser/browser_task_traits.h", + "+content/public/browser/browser_thread.h", + "+content/public/browser/storage_partition.h", + ], +} \ No newline at end of file
diff --git a/remoting/host/chromeos/remote_support_host_ash.cc b/remoting/host/chromeos/remote_support_host_ash.cc new file mode 100644 index 0000000..4dc86c7 --- /dev/null +++ b/remoting/host/chromeos/remote_support_host_ash.cc
@@ -0,0 +1,71 @@ +// 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 "remoting/host/chromeos/remote_support_host_ash.h" + +#include <utility> + +#include <stddef.h> + +#include "base/notreached.h" +#include "base/strings/stringize_macros.h" +#include "remoting/host/chromeos/remoting_service.h" +#include "remoting/host/chromoting_host_context.h" +#include "remoting/host/it2me/it2me_constants.h" +#include "remoting/host/it2me/it2me_native_messaging_host_ash.h" +#include "remoting/host/policy_watcher.h" + +namespace remoting { + +RemoteSupportHostAsh::RemoteSupportHostAsh(base::OnceClosure cleanup_callback) + : cleanup_callback_(std::move(cleanup_callback)) {} + +RemoteSupportHostAsh::~RemoteSupportHostAsh() = default; + +void RemoteSupportHostAsh::StartSession(mojom::SupportSessionParamsPtr params, + StartSessionCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Ensure there is at most one active remote support connection. + // Since we are initiating the disconnect, don't run the cleanup callback. + if (it2me_native_message_host_ash_) { + auto temp = std::move(it2me_native_message_host_ash_); + temp->Disconnect(); + } + + it2me_native_message_host_ash_ = + std::make_unique<It2MeNativeMessageHostAsh>(); + + mojo::PendingReceiver<mojom::SupportHostObserver> pending_receiver = + it2me_native_message_host_ash_->Start( + RemotingService::Get().CreateHostContext(), + RemotingService::Get().CreatePolicyWatcher()); + + mojom::StartSupportSessionResponsePtr response = + mojom::StartSupportSessionResponse::New(); + response->set_observer(std::move(pending_receiver)); + + it2me_native_message_host_ash_->Connect( + std::move(params), + base::BindOnce(std::move(callback), std::move(response)), + base::BindOnce(&RemoteSupportHostAsh::OnSessionDisconnected, + base::Unretained(this))); +} + +// static +mojom::SupportHostDetailsPtr RemoteSupportHostAsh::GetHostDetails() { + return mojom::SupportHostDetails::New( + STRINGIZE(VERSION), std::vector<std::string>({kFeatureAccessTokenAuth})); +} + +void RemoteSupportHostAsh::OnSessionDisconnected() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (it2me_native_message_host_ash_) { + // Do not access any instance members after |cleanup_callback_| is run as + // this instance will be destroyed by running this. + std::move(cleanup_callback_).Run(); + } +} + +} // namespace remoting
diff --git a/remoting/host/chromeos/remote_support_host_ash.h b/remoting/host/chromeos/remote_support_host_ash.h new file mode 100644 index 0000000..952400e --- /dev/null +++ b/remoting/host/chromeos/remote_support_host_ash.h
@@ -0,0 +1,57 @@ +// 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 REMOTING_HOST_CHROMEOS_REMOTE_SUPPORT_HOST_ASH_H_ +#define REMOTING_HOST_CHROMEOS_REMOTE_SUPPORT_HOST_ASH_H_ + +#include "base/callback.h" +#include "base/sequence_checker.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote_set.h" +#include "remoting/host/it2me/it2me_native_messaging_host_ash.h" +#include "remoting/host/mojom/remote_support.mojom.h" + +namespace remoting { + +class It2MeNativeMessageHostAsh; + +// This class represents a remote support host instance which can be connected +// to and controlled over an IPC channel. It wraps a remote support host +// implementation and enforces the single connection requirement. Method calls +// and destruction must occur on the same sequence as creation. This object's +// lifetime is tied to that of the wrapped host, meaning this instance will be +// destroyed when the IPC channel is disconnected. +class RemoteSupportHostAsh { + public: + explicit RemoteSupportHostAsh(base::OnceClosure cleanup_callback); + RemoteSupportHostAsh(const RemoteSupportHostAsh&) = delete; + RemoteSupportHostAsh& operator=(const RemoteSupportHostAsh&) = delete; + ~RemoteSupportHostAsh(); + + using StartSessionCallback = + base::OnceCallback<void(mojom::StartSupportSessionResponsePtr response)>; + + // Returns a structure which includes the host version and supported features. + static mojom::SupportHostDetailsPtr GetHostDetails(); + + // Allows the caller to start a new remote support session. |callback| is + // called with the result. + void StartSession(mojom::SupportSessionParamsPtr params, + StartSessionCallback callback); + + private: + void OnSessionDisconnected(); + + SEQUENCE_CHECKER(sequence_checker_); + + std::unique_ptr<It2MeNativeMessageHostAsh> it2me_native_message_host_ash_ + GUARDED_BY_CONTEXT(sequence_checker_); + + base::OnceClosure cleanup_callback_; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_CHROMEOS_REMOTE_SUPPORT_HOST_ASH_H_
diff --git a/remoting/host/chromeos/remoting_service.cc b/remoting/host/chromeos/remoting_service.cc new file mode 100644 index 0000000..53dcea3 --- /dev/null +++ b/remoting/host/chromeos/remoting_service.cc
@@ -0,0 +1,87 @@ +// 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 "remoting/host/chromeos/remoting_service.h" + +#include <memory> +#include <utility> + +#include "base/no_destructor.h" +#include "base/sequence_checker.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "chrome/browser/browser_process.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "remoting/base/auto_thread_task_runner.h" +#include "remoting/host/chromeos/remote_support_host_ash.h" +#include "remoting/host/chromoting_host_context.h" +#include "remoting/host/policy_watcher.h" + +namespace remoting { + +namespace { + +class RemotingServiceImpl : public RemotingService { + public: + RemotingServiceImpl(); + RemotingServiceImpl(const RemotingServiceImpl&) = delete; + RemotingServiceImpl& operator=(const RemotingServiceImpl&) = delete; + ~RemotingServiceImpl() override; + + // RemotingService implementation. + RemoteSupportHostAsh& GetSupportHost() override; + std::unique_ptr<ChromotingHostContext> CreateHostContext() override; + std::unique_ptr<PolicyWatcher> CreatePolicyWatcher() override; + + private: + void ReleaseSupportHost(); + + SEQUENCE_CHECKER(sequence_checker_); + + std::unique_ptr<RemoteSupportHostAsh> remote_support_host_ + GUARDED_BY_CONTEXT(sequence_checker_); +}; + +RemotingServiceImpl::RemotingServiceImpl() = default; +RemotingServiceImpl::~RemotingServiceImpl() = default; + +RemoteSupportHostAsh& RemotingServiceImpl::GetSupportHost() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!remote_support_host_) { + remote_support_host_ = + std::make_unique<RemoteSupportHostAsh>(base::BindOnce( + &RemotingServiceImpl::ReleaseSupportHost, base::Unretained(this))); + } + return *remote_support_host_; +} + +std::unique_ptr<ChromotingHostContext> +RemotingServiceImpl::CreateHostContext() { + return ChromotingHostContext::CreateForChromeOS( + content::GetIOThreadTaskRunner({}), content::GetUIThreadTaskRunner({}), + base::ThreadPool::CreateSingleThreadTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT})); +} + +std::unique_ptr<PolicyWatcher> RemotingServiceImpl::CreatePolicyWatcher() { + return PolicyWatcher::CreateWithPolicyService( + g_browser_process->policy_service()); +} + +void RemotingServiceImpl::ReleaseSupportHost() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + remote_support_host_.reset(); +} + +} // namespace + +RemotingService& RemotingService::Get() { + static base::NoDestructor<RemotingServiceImpl> instance; + return *instance; +} + +} // namespace remoting
diff --git a/remoting/host/chromeos/remoting_service.h b/remoting/host/chromeos/remoting_service.h new file mode 100644 index 0000000..269d649 --- /dev/null +++ b/remoting/host/chromeos/remoting_service.h
@@ -0,0 +1,38 @@ +// 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 REMOTING_HOST_CHROMEOS_REMOTING_SERVICE_H_ +#define REMOTING_HOST_CHROMEOS_REMOTING_SERVICE_H_ + +#include <memory> + +namespace remoting { + +class ChromotingHostContext; +class PolicyWatcher; +class RemoteSupportHostAsh; + +// The RemotingService is a singleton which provides access to remoting +// functionality to external callers in Chrome OS. This service also manages +// state and lifetime of the instances which implement that functionality. +// This service expects to be called on the sequence it was first called on +// which is bound to the Main/UI sequence in production code. +class RemotingService { + public: + static RemotingService& Get(); + virtual ~RemotingService() = default; + + // Must be called on the sequence the service was created on. + virtual RemoteSupportHostAsh& GetSupportHost() = 0; + + // Can be called on any sequence. + virtual std::unique_ptr<ChromotingHostContext> CreateHostContext() = 0; + + // Can be called on any sequence. + virtual std::unique_ptr<PolicyWatcher> CreatePolicyWatcher() = 0; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_CHROMEOS_REMOTING_SERVICE_H_
diff --git a/remoting/host/it2me/BUILD.gn b/remoting/host/it2me/BUILD.gn index b320b88..1d2be79c 100644 --- a/remoting/host/it2me/BUILD.gn +++ b/remoting/host/it2me/BUILD.gn
@@ -24,6 +24,18 @@ ] } +source_set("helpers") { + sources = [ + "it2me_helpers.cc", + "it2me_helpers.h", + ] + deps = [ + ":constants", + "//base", + "//remoting/base", + ] +} + source_set("common") { sources = [ "it2me_confirmation_dialog.h", @@ -56,7 +68,10 @@ "//remoting/build/config:version", ] - public_deps = [ ":constants" ] + public_deps = [ + ":constants", + ":helpers", + ] deps = [ "//base:i18n", @@ -110,11 +125,18 @@ "it2me_native_messaging_host_lacros.h", ] deps = [ + ":constants", + ":helpers", "//base", + "//chromeos/crosapi/mojom", + "//chromeos/lacros", "//extensions/browser/api/messaging:native_messaging", + "//remoting/protocol:errors", ] } else { sources += [ + "it2me_native_messaging_host_ash.cc", + "it2me_native_messaging_host_ash.h", "it2me_native_messaging_host_chromeos.cc", "it2me_native_messaging_host_chromeos.h", ] @@ -124,6 +146,7 @@ "//extensions/browser/api/messaging:native_messaging", "//remoting/base:base", "//remoting/host:common", + "//remoting/host/mojom:mojom", "//skia", ]
diff --git a/remoting/host/it2me/DEPS b/remoting/host/it2me/DEPS index 52537fb8..f311d93 100644 --- a/remoting/host/it2me/DEPS +++ b/remoting/host/it2me/DEPS
@@ -4,5 +4,9 @@ # targets. It should be removed when support for classic ash is removed; # which means that remoting never touches ozone. "+ui/ozone/public/ozone_platform.h", - ] + ], + "it2me_native_messaging_host_lacros.cc": [ + "+chromeos/crosapi/mojom/remoting.mojom.h", + "+chromeos/lacros/lacros_chrome_service_impl.h", + ], }
diff --git a/remoting/host/it2me/it2me_constants.cc b/remoting/host/it2me/it2me_constants.cc index dafba874..33a86fd 100644 --- a/remoting/host/it2me/it2me_constants.cc +++ b/remoting/host/it2me/it2me_constants.cc
@@ -6,6 +6,8 @@ namespace remoting { +const char kFeatureAccessTokenAuth[] = "accessTokenAuth"; + const char kMessageId[] = "id"; const char kMessageType[] = "type";
diff --git a/remoting/host/it2me/it2me_constants.h b/remoting/host/it2me/it2me_constants.h index 170ce67..e1bb9933 100644 --- a/remoting/host/it2me/it2me_constants.h +++ b/remoting/host/it2me/it2me_constants.h
@@ -7,6 +7,23 @@ namespace remoting { +// These state values are defined in the website client as well. Remember to +// update both enums when making changes. +enum class It2MeHostState { + kDisconnected, + kStarting, + kRequestedAccessCode, + kReceivedAccessCode, + kConnecting, + kConnected, + kError, + kInvalidDomainError, +}; + +// Indicates that an OAuth access token can be provided to the host which will +// use it for service requests (e.g. ICE config, signaling, host registration). +extern const char kFeatureAccessTokenAuth[]; + // ID used to identify the current message. Must be included in the response if // the sender includes it. extern const char kMessageId[];
diff --git a/remoting/host/it2me/it2me_helpers.cc b/remoting/host/it2me/it2me_helpers.cc new file mode 100644 index 0000000..51cfcec --- /dev/null +++ b/remoting/host/it2me/it2me_helpers.cc
@@ -0,0 +1,61 @@ +// 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 "remoting/host/it2me/it2me_helpers.h" + +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/notreached.h" +#include "base/values.h" +#include "remoting/base/name_value_map.h" +#include "remoting/host/it2me/it2me_constants.h" + +namespace remoting { + +namespace { + +const NameMapElement<It2MeHostState> kIt2MeHostStates[] = { + {It2MeHostState::kDisconnected, kHostStateDisconnected}, + {It2MeHostState::kStarting, kHostStateStarting}, + {It2MeHostState::kRequestedAccessCode, kHostStateRequestedAccessCode}, + {It2MeHostState::kReceivedAccessCode, kHostStateReceivedAccessCode}, + {It2MeHostState::kConnecting, kHostStateConnecting}, + {It2MeHostState::kConnected, kHostStateConnected}, + {It2MeHostState::kError, kHostStateError}, + {It2MeHostState::kInvalidDomainError, kHostStateDomainError}, +}; + +} + +bool ParseIt2MeNativeMessageJson(const std::string& message, + std::string& message_type, + base::Value& dictionary_value) { + auto opt_message = base::JSONReader::Read(message); + if (!opt_message.has_value()) { + LOG(ERROR) << "Received a message that's not valid JSON."; + return false; + } + + auto message_value = std::move(opt_message.value()); + if (!message_value.is_dict()) { + LOG(ERROR) << "Received a message that's not a dictionary."; + return false; + } + + const std::string* message_type_value = + message_value.FindStringPath(kMessageType); + if (message_type_value) { + message_type = *message_type_value; + } + + dictionary_value = std::move(message_value); + + return true; +} + +std::string It2MeHostStateToString(It2MeHostState host_state) { + return ValueToName(kIt2MeHostStates, host_state); +} + +} // namespace remoting
diff --git a/remoting/host/it2me/it2me_helpers.h b/remoting/host/it2me/it2me_helpers.h new file mode 100644 index 0000000..1bf2e3c --- /dev/null +++ b/remoting/host/it2me/it2me_helpers.h
@@ -0,0 +1,31 @@ +// 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 REMOTING_HOST_IT2ME_IT2ME_HELPERS_H_ +#define REMOTING_HOST_IT2ME_IT2ME_HELPERS_H_ + +#include <string> + +namespace base { +class Value; +} + +namespace remoting { + +enum class It2MeHostState; + +// Parses a serialized JSON message from either the CRD website client or an +// It2MeNativeMessageHost instance. Returns true if the message was +// successfully parsed. If parsing fails, the out params will not be valid. +bool ParseIt2MeNativeMessageJson(const std::string& message, + std::string& message_type, + base::Value& parsed_message); + +// Provides a human readable name for a given It2MeHostState. This is used both +// for logging and in host state changed JSON messages. +std::string It2MeHostStateToString(It2MeHostState host_state); + +} // namespace remoting + +#endif // REMOTING_HOST_IT2ME_IT2ME_HELPERS_H_
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc index c6216de..cc642ab 100644 --- a/remoting/host/it2me/it2me_host.cc +++ b/remoting/host/it2me/it2me_host.cc
@@ -27,6 +27,7 @@ #include "remoting/host/host_secret.h" #include "remoting/host/host_status_logger.h" #include "remoting/host/it2me/it2me_confirmation_dialog.h" +#include "remoting/host/it2me/it2me_helpers.h" #include "remoting/host/it2me_desktop_environment.h" #include "remoting/protocol/auth_util.h" #include "remoting/protocol/chromium_port_allocator_factory.h" @@ -134,9 +135,9 @@ const protocol::IceConfig& ice_config, CreateDeferredConnectContext create_context) { DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); - DCHECK_EQ(kDisconnected, state_); + DCHECK_EQ(It2MeHostState::kDisconnected, state_); - SetState(kStarting, ErrorCode::OK); + SetState(It2MeHostState::kStarting, ErrorCode::OK); auto connection_context = std::move(create_context).Run(host_context_.get()); log_to_server_ = std::move(connection_context->log_to_server); @@ -155,7 +156,7 @@ } } if (!matched) { - SetState(kInvalidDomainError, ErrorCode::OK); + SetState(It2MeHostState::kInvalidDomainError, ErrorCode::OK); return; } } @@ -237,7 +238,7 @@ signal_strategy_->Connect(); host_->Start(username); - SetState(kRequestedAccessCode, ErrorCode::OK); + SetState(It2MeHostState::kRequestedAccessCode, ErrorCode::OK); return; } @@ -248,10 +249,10 @@ if (failed_login_attempts_ == kMaxLoginAttempts) { DisconnectOnNetworkThread(); } else if (connecting_jid_ == NormalizeSignalingId(jid)) { - DCHECK_EQ(state_, kConnecting); + DCHECK_EQ(state_, It2MeHostState::kConnecting); connecting_jid_.clear(); confirmation_dialog_proxy_.reset(); - SetState(kReceivedAccessCode, ErrorCode::OK); + SetState(It2MeHostState::kReceivedAccessCode, ErrorCode::OK); } } @@ -260,7 +261,7 @@ // ChromotingHost doesn't allow concurrent connections and the host is // destroyed in OnClientDisconnected() after the first connection. - CHECK_NE(state_, kConnected); + CHECK_NE(state_, It2MeHostState::kConnected); std::string client_username; if (!SplitSignalingIdResource(jid, &client_username, /*resource=*/nullptr)) { @@ -275,7 +276,7 @@ FROM_HERE, base::BindOnce(&It2MeHost::Observer::OnClientAuthenticated, observer_, client_username)); - SetState(kConnected, ErrorCode::OK); + SetState(It2MeHostState::kConnected, ErrorCode::OK); } void It2MeHost::OnClientDisconnected(const std::string& jid) { @@ -417,40 +418,48 @@ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); switch (state_) { - case kDisconnected: - DCHECK(state == kStarting || - state == kError) << state; + case It2MeHostState::kDisconnected: + DCHECK(state == It2MeHostState::kStarting || + state == It2MeHostState::kError) + << It2MeHostStateToString(state); break; - case kStarting: - DCHECK(state == kRequestedAccessCode || - state == kDisconnected || - state == kError || - state == kInvalidDomainError) << state; + case It2MeHostState::kStarting: + DCHECK(state == It2MeHostState::kRequestedAccessCode || + state == It2MeHostState::kDisconnected || + state == It2MeHostState::kError || + state == It2MeHostState::kInvalidDomainError) + << It2MeHostStateToString(state); break; - case kRequestedAccessCode: - DCHECK(state == kReceivedAccessCode || - state == kDisconnected || - state == kError) << state; + case It2MeHostState::kRequestedAccessCode: + DCHECK(state == It2MeHostState::kReceivedAccessCode || + state == It2MeHostState::kDisconnected || + state == It2MeHostState::kError) + << It2MeHostStateToString(state); break; - case kReceivedAccessCode: - DCHECK(state == kConnecting || - state == kDisconnected || - state == kError) << state; + case It2MeHostState::kReceivedAccessCode: + DCHECK(state == It2MeHostState::kConnecting || + state == It2MeHostState::kDisconnected || + state == It2MeHostState::kError) + << It2MeHostStateToString(state); break; - case kConnecting: - DCHECK(state == kConnected || - state == kDisconnected || - state == kError) << state; + case It2MeHostState::kConnecting: + DCHECK(state == It2MeHostState::kConnected || + state == It2MeHostState::kDisconnected || + state == It2MeHostState::kError) + << It2MeHostStateToString(state); break; - case kConnected: - DCHECK(state == kDisconnected || - state == kError) << state; + case It2MeHostState::kConnected: + DCHECK(state == It2MeHostState::kDisconnected || + state == It2MeHostState::kError) + << It2MeHostStateToString(state); break; - case kError: - DCHECK(state == kDisconnected) << state; + case It2MeHostState::kError: + DCHECK(state == It2MeHostState::kDisconnected) + << It2MeHostStateToString(state); break; - case kInvalidDomainError: - DCHECK(state == kDisconnected) << state; + case It2MeHostState::kInvalidDomainError: + DCHECK(state == It2MeHostState::kDisconnected) + << It2MeHostStateToString(state); break; }; @@ -463,8 +472,10 @@ } bool It2MeHost::IsRunning() const { - return state_ == kRequestedAccessCode || state_ == kReceivedAccessCode || - state_ == kConnected || state_ == kConnecting; + return state_ == It2MeHostState::kRequestedAccessCode || + state_ == It2MeHostState::kReceivedAccessCode || + state_ == It2MeHostState::kConnected || + state_ == It2MeHostState::kConnecting; } void It2MeHost::OnReceivedSupportID(const std::string& support_id, @@ -473,7 +484,7 @@ DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); if (error_code != ErrorCode::OK) { - SetState(kError, error_code); + SetState(It2MeHostState::kError, error_code); DisconnectOnNetworkThread(); return; } @@ -486,7 +497,7 @@ std::string local_certificate = host_key_pair_->GenerateCertificate(); if (local_certificate.empty()) { LOG(ERROR) << "Failed to generate host certificate."; - SetState(kError, ErrorCode::HOST_CERTIFICATE_ERROR); + SetState(It2MeHostState::kError, ErrorCode::HOST_CERTIFICATE_ERROR); DisconnectOnNetworkThread(); return; } @@ -503,7 +514,7 @@ FROM_HERE, base::BindOnce(&It2MeHost::Observer::OnStoreAccessCode, observer_, access_code, lifetime)); - SetState(kReceivedAccessCode, ErrorCode::OK); + SetState(It2MeHostState::kReceivedAccessCode, ErrorCode::OK); } void It2MeHost::DisconnectOnNetworkThread() { @@ -511,7 +522,7 @@ // Disconnect() may be called even after the host has already been stopped. // Ignore repeated calls. - if (state_ == kDisconnected) { + if (state_ == It2MeHostState::kDisconnected) { return; } @@ -532,7 +543,7 @@ host_context_->ui_task_runner()->DeleteSoon( FROM_HERE, desktop_environment_factory_.release()); - SetState(kDisconnected, ErrorCode::OK); + SetState(It2MeHostState::kDisconnected, ErrorCode::OK); } void It2MeHost::ValidateConnectionDetails( @@ -582,8 +593,8 @@ // If we receive valid connection details multiple times, then we don't know // which remote user (if either) is valid so disconnect everyone. - if (state_ != kReceivedAccessCode) { - DCHECK_EQ(kConnecting, state_); + if (state_ != It2MeHostState::kReceivedAccessCode) { + DCHECK_EQ(It2MeHostState::kConnecting, state_); LOG(ERROR) << "Received too many connection requests."; std::move(result_callback) .Run(ValidationResult::ERROR_TOO_MANY_CONNECTIONS); @@ -593,7 +604,7 @@ HOST_LOG << "Client " << client_username << " connecting."; connecting_jid_ = remote_jid; - SetState(kConnecting, ErrorCode::OK); + SetState(It2MeHostState::kConnecting, ErrorCode::OK); // Show a confirmation dialog to the user to allow them to confirm/reject it. // If dialogs are suppressed, just call the callback directly.
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h index 7ec16f9..ae8d3fb9 100644 --- a/remoting/host/it2me/it2me_host.h +++ b/remoting/host/it2me/it2me_host.h
@@ -16,6 +16,7 @@ #include "remoting/host/host_status_observer.h" #include "remoting/host/it2me/it2me_confirmation_dialog.h" #include "remoting/host/it2me/it2me_confirmation_dialog_proxy.h" +#include "remoting/host/it2me/it2me_constants.h" #include "remoting/host/register_support_host_request.h" #include "remoting/protocol/errors.h" #include "remoting/protocol/port_range.h" @@ -41,19 +42,6 @@ struct IceConfig; } // namespace protocol -// These state values are duplicated in host_session.js. Remember to update -// both copies when making changes. -enum It2MeHostState { - kDisconnected, - kStarting, - kRequestedAccessCode, - kReceivedAccessCode, - kConnecting, - kConnected, - kError, - kInvalidDomainError, -}; - // Internal implementation of the plugin's It2Me host function. class It2MeHost : public base::RefCountedThreadSafe<It2MeHost>, public HostStatusObserver { @@ -188,7 +176,7 @@ std::unique_ptr<SignalStrategy> signal_strategy_; std::unique_ptr<LogToServer> log_to_server_; - It2MeHostState state_ = kDisconnected; + It2MeHostState state_ = It2MeHostState::kDisconnected; scoped_refptr<RsaKeyPair> host_key_pair_; std::unique_ptr<RegisterSupportHostRequest> register_request_;
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc index 4b1e1ac7..804df5b7 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.cc +++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -26,12 +26,12 @@ #include "net/socket/client_socket_factory.h" #include "net/url_request/url_request_context_getter.h" #include "remoting/base/auto_thread_task_runner.h" -#include "remoting/base/name_value_map.h" #include "remoting/base/passthrough_oauth_token_getter.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/host_exit_codes.h" #include "remoting/host/it2me/it2me_confirmation_dialog.h" #include "remoting/host/it2me/it2me_constants.h" +#include "remoting/host/it2me/it2me_helpers.h" #include "remoting/host/policy_watcher.h" #include "remoting/host/remoting_register_support_host_request.h" #include "remoting/host/xmpp_register_support_host_request.h" @@ -57,17 +57,6 @@ namespace { -const NameMapElement<It2MeHostState> kIt2MeHostStates[] = { - {kDisconnected, kHostStateDisconnected}, - {kStarting, kHostStateStarting}, - {kRequestedAccessCode, kHostStateRequestedAccessCode}, - {kReceivedAccessCode, kHostStateReceivedAccessCode}, - {kConnecting, kHostStateConnecting}, - {kConnected, kHostStateConnected}, - {kError, kHostStateError}, - {kInvalidDomainError, kHostStateDomainError}, -}; - #if defined(OS_WIN) const base::FilePath::CharType kBaseHostBinaryName[] = FILE_PATH_LITERAL("remote_assistance_host.exe"); @@ -421,7 +410,8 @@ incoming_message_callback_.Run(iq); } else { LOG(WARNING) << "Dropping message because signaling is not connected. " - << "Current It2MeHost state: " << state_; + << "Current It2MeHost state: " + << It2MeHostStateToString(state_); } SendMessageToClient(std::move(response)); } @@ -466,24 +456,24 @@ std::unique_ptr<base::DictionaryValue> message(new base::DictionaryValue()); message->SetString(kMessageType, kHostStateChangedMessage); - message->SetString(kState, HostStateToString(state)); + message->SetString(kState, It2MeHostStateToString(state)); switch (state_) { - case kReceivedAccessCode: + case It2MeHostState::kReceivedAccessCode: message->SetString(kAccessCode, access_code_); message->SetInteger(kAccessCodeLifetime, access_code_lifetime_.InSeconds()); break; - case kConnected: + case It2MeHostState::kConnected: message->SetString(kClient, client_username_); break; - case kDisconnected: + case It2MeHostState::kDisconnected: client_username_.clear(); break; - case kError: + case It2MeHostState::kError: // kError is an internal-only state, sent to the web-app by a separate // "error" message so that errors that occur before the "connect" message // is sent can be communicated. @@ -543,13 +533,17 @@ } /* static */ -std::string It2MeNativeMessagingHost::HostStateToString( - It2MeHostState host_state) { - return ValueToName(kIt2MeHostStates, host_state); -} void It2MeNativeMessagingHost::OnPolicyUpdate( std::unique_ptr<base::DictionaryValue> policies) { + // If an It2MeHost exists, provide it with the updated policies first. + // That way it won't appear that the policies have changed if the pending + // connect callback is run. If done the other way around, there is a race + // condition which could cause the connection to be canceled before it starts. + if (it2me_host_) { + it2me_host_->OnPolicyUpdate(std::move(policies)); + } + if (!policy_received_) { policy_received_ = true; @@ -557,10 +551,6 @@ std::move(pending_connect_).Run(); } } - - if (it2me_host_) { - it2me_host_->OnPolicyUpdate(std::move(policies)); - } } absl::optional<bool>
diff --git a/remoting/host/it2me/it2me_native_messaging_host.h b/remoting/host/it2me/it2me_native_messaging_host.h index a077014..93b2b54 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.h +++ b/remoting/host/it2me/it2me_native_messaging_host.h
@@ -64,8 +64,6 @@ // processed. void SetPolicyErrorClosureForTesting(base::OnceClosure closure); - static std::string HostStateToString(It2MeHostState host_state); - private: // These "Process.." methods handle specific request types. The |response| // dictionary is pre-filled by ProcessMessage() with the parts of the
diff --git a/remoting/host/it2me/it2me_native_messaging_host_ash.cc b/remoting/host/it2me/it2me_native_messaging_host_ash.cc new file mode 100644 index 0000000..8282f28 --- /dev/null +++ b/remoting/host/it2me/it2me_native_messaging_host_ash.cc
@@ -0,0 +1,247 @@ +// 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 <utility> + +#include "remoting/host/it2me/it2me_native_messaging_host_ash.h" + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/lazy_instance.h" +#include "base/stl_util.h" +#include "base/time/time.h" +#include "base/values.h" +#include "extensions/browser/api/messaging/native_message_host.h" +#include "remoting/host/chromoting_host_context.h" +#include "remoting/host/it2me/it2me_helpers.h" +#include "remoting/host/it2me/it2me_native_messaging_host.h" +#include "remoting/host/policy_watcher.h" + +namespace remoting { + +It2MeNativeMessageHostAsh::It2MeNativeMessageHostAsh() = default; +It2MeNativeMessageHostAsh::~It2MeNativeMessageHostAsh() = default; + +mojo::PendingReceiver<mojom::SupportHostObserver> +It2MeNativeMessageHostAsh::Start( + std::unique_ptr<ChromotingHostContext> context, + std::unique_ptr<PolicyWatcher> policy_watcher) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!native_message_host_); + + // Create the remote IPC channel before starting the NMH so any errors are + // queued for sending once the receiver end of the channel is bound. + mojo::PendingReceiver<mojom::SupportHostObserver> observer = + remote_.BindNewPipeAndPassReceiver(); + + std::unique_ptr<It2MeHostFactory> host_factory(new It2MeHostFactory()); + native_message_host_ = std::make_unique<It2MeNativeMessagingHost>( + /*needs_elevation=*/false, std::move(policy_watcher), std::move(context), + std::move(host_factory)); + native_message_host_->Start(this); + + return observer; +} + +void It2MeNativeMessageHostAsh::Connect( + mojom::SupportSessionParamsPtr params, + base::OnceClosure connected_callback, + base::OnceClosure disconnected_callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(native_message_host_); + DCHECK(!connected_callback_); + DCHECK(!disconnected_callback_); + + connected_callback_ = std::move(connected_callback); + disconnected_callback_ = std::move(disconnected_callback); + + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey(kMessageType, kConnectMessage); + + message.SetStringKey(kUserName, params->user_name); + message.SetStringKey(kAuthServiceWithToken, params->oauth_access_token); + + std::string message_json; + base::JSONWriter::Write(message, &message_json); + native_message_host_->OnMessage(message_json); +} + +void It2MeNativeMessageHostAsh::Disconnect() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey(kMessageType, kDisconnectMessage); + + std::string message_json; + base::JSONWriter::Write(message, &message_json); + native_message_host_->OnMessage(message_json); + + // Notify the owner that the host has been disconnected. This will result in + // the destruction of this object so do not access member variables after this + // callback is run. + std::move(disconnected_callback_).Run(); +} + +void It2MeNativeMessageHostAsh::PostMessageFromNativeHost( + const std::string& message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + std::string type; + base::Value contents; + if (!ParseIt2MeNativeMessageJson(message, type, contents)) { + CloseChannel(std::string()); + return; + } + + if (type.empty()) { + LOG(ERROR) << "'type' not found in request."; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + + if (type == kConnectResponse) { + HandleConnectResponse(); + } else if (type == kDisconnectResponse) { + HandleDisconnectResponse(); + } else if (type == kIncomingIqResponse) { + // These responses do not need to be handled as the Lacros NMH sends a + // response when the request message is first received. + } else if (type == kHostStateChangedMessage) { + HandleHostStateChangeMessage(std::move(contents)); + } else if (type == kNatPolicyChangedMessage) { + HandleNatPolicyChangedMessage(std::move(contents)); + } else if (type == kPolicyErrorMessage) { + HandlePolicyErrorMessage(std::move(contents)); + } else if (type == kErrorMessage) { + HandleErrorMessage(std::move(contents)); + } else { + LOG(ERROR) << "Unsupported message type: " << type; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + } +} + +void It2MeNativeMessageHostAsh::CloseChannel(const std::string& error_message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + LOG_IF(ERROR, !error_message.empty()) + << "CloseChannel called with error: " << error_message; + Disconnect(); +} + +void It2MeNativeMessageHostAsh::HandleConnectResponse() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + std::move(connected_callback_).Run(); +} + +void It2MeNativeMessageHostAsh::HandleDisconnectResponse() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + remote_->OnHostStateDisconnected(); +} + +void It2MeNativeMessageHostAsh::HandleHostStateChangeMessage( + base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + std::string* new_state = message.FindStringKey(kState); + if (!new_state) { + LOG(ERROR) << "Missing |" << kState << "| value in message."; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + + if (*new_state == kHostStateStarting) { + remote_->OnHostStateStarting(); + } else if (*new_state == kHostStateDisconnected) { + remote_->OnHostStateDisconnected(); + } else if (*new_state == kHostStateRequestedAccessCode) { + remote_->OnHostStateRequestedAccessCode(); + } else if (*new_state == kHostStateReceivedAccessCode) { + std::string* access_code = message.FindStringKey(kAccessCode); + if (!access_code) { + LOG(ERROR) << "Missing |" << kAccessCode << "| value in message."; + CloseChannel( + ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + absl::optional<int> access_code_lifetime = + message.FindIntKey(kAccessCodeLifetime); + if (!access_code_lifetime) { + LOG(ERROR) << "Missing |" << kAccessCodeLifetime << "| value in message."; + CloseChannel( + ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + remote_->OnHostStateReceivedAccessCode( + *access_code, + base::TimeDelta::FromSeconds(access_code_lifetime.value())); + } else if (*new_state == kHostStateConnecting) { + remote_->OnHostStateConnecting(); + } else if (*new_state == kHostStateConnected) { + std::string* remote_username = message.FindStringKey(kClient); + if (!remote_username) { + LOG(ERROR) << "Missing |" << kClient << "| value in message."; + CloseChannel( + ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + remote_->OnHostStateConnected(*remote_username); + } else if (*new_state == kHostStateError) { + absl::optional<int> error_code = message.FindIntKey(kErrorMessageCode); + if (!error_code) { + LOG(ERROR) << "Missing |" << kErrorMessageCode << "| value in message."; + CloseChannel( + ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + remote_->OnHostStateError(error_code.value()); + } else if (*new_state == kHostStateDomainError) { + remote_->OnInvalidDomainError(); + } else { + NOTREACHED() << "Unknown state: " << *new_state; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } +} + +void It2MeNativeMessageHostAsh::HandleNatPolicyChangedMessage( + base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + absl::optional<bool> nat_enabled = + message.FindBoolKey(kNatPolicyChangedMessageNatEnabled); + if (!nat_enabled.has_value()) { + LOG(ERROR) << "Missing |" << kNatPolicyChangedMessageNatEnabled + << "| value in message."; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + + absl::optional<bool> relay_enabled = + message.FindBoolKey(kNatPolicyChangedMessageRelayEnabled); + if (!nat_enabled.has_value()) { + LOG(ERROR) << "Missing |" << kNatPolicyChangedMessageRelayEnabled + << "| value in message."; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + + mojom::NatPolicyStatePtr nat_policy = mojom::NatPolicyState::New(); + nat_policy->nat_enabled = nat_enabled.value(); + nat_policy->relay_enabled = relay_enabled.value(); + remote_->OnNatPolicyChanged(std::move(nat_policy)); +} + +void It2MeNativeMessageHostAsh::HandlePolicyErrorMessage(base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + remote_->OnPolicyError(); +} + +void It2MeNativeMessageHostAsh::HandleErrorMessage(base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + absl::optional<int> error_code = message.FindIntKey(kErrorMessageCode); + if (!error_code.has_value()) { + LOG(ERROR) << "Missing |" << kErrorMessageCode << "| value in message."; + CloseChannel(ErrorCodeToString(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL)); + return; + } + + remote_->OnHostStateError(error_code.value()); +} + +} // namespace remoting
diff --git a/remoting/host/it2me/it2me_native_messaging_host_ash.h b/remoting/host/it2me/it2me_native_messaging_host_ash.h new file mode 100644 index 0000000..3c3d8df --- /dev/null +++ b/remoting/host/it2me/it2me_native_messaging_host_ash.h
@@ -0,0 +1,89 @@ +// 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 REMOTING_HOST_IT2ME_IT2ME_NATIVE_MESSAGING_HOST_ASH_H_ +#define REMOTING_HOST_IT2ME_IT2ME_NATIVE_MESSAGING_HOST_ASH_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/sequence_checker.h" +#include "extensions/browser/api/messaging/native_message_host.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "remoting/host/mojom/remote_support.mojom.h" + +namespace base { +class Value; +} + +namespace extensions { +class NativeMessageHost; +} + +namespace remoting { + +class ChromotingHostContext; +class PolicyWatcher; + +// This class wraps the It2MeNativeMessageHost instance used on other platforms +// and provides a way to interact with it using Mojo IPC. This instance +// receives messages from the wrapped NMH by observing it via the Client +// interface. The messages and events are then converted from JSON to Mojo and +// forwarded to the It2MeNativeMessageHostLacros instance over IPC. +// All interactions with it must occur on the sequence it was created on. +class It2MeNativeMessageHostAsh : public extensions::NativeMessageHost::Client { + public: + It2MeNativeMessageHostAsh(); + It2MeNativeMessageHostAsh(const It2MeNativeMessageHostAsh&) = delete; + It2MeNativeMessageHostAsh& operator=(const It2MeNativeMessageHostAsh&) = + delete; + ~It2MeNativeMessageHostAsh() override; + + // Creates a new NMH instance, creates a new SupportHostObserver remote and + // returns the pending_remote. Start() must be called before the first call + // to |Connect()|. + mojo::PendingReceiver<mojom::SupportHostObserver> Start( + std::unique_ptr<ChromotingHostContext> context, + std::unique_ptr<PolicyWatcher> policy_watcher); + + // extensions::NativeMessageHost::Client. + void PostMessageFromNativeHost(const std::string& message) override; + void CloseChannel(const std::string& error_message) override; + + // Begins the connection process using the wrapped native message host. + // |connected_callback| is run after the connection process has completed. + void Connect(mojom::SupportSessionParamsPtr params, + base::OnceClosure connected_callback, + base::OnceClosure disconnected_callback); + // Disconnects an active session if one exists. + void Disconnect(); + + private: + // Handlers for messages received from the wrapped native message host. + void HandleConnectResponse(); + void HandleDisconnectResponse(); + void HandleHostStateChangeMessage(base::Value message); + void HandleNatPolicyChangedMessage(base::Value message); + void HandlePolicyErrorMessage(base::Value message); + void HandleErrorMessage(base::Value message); + + SEQUENCE_CHECKER(sequence_checker_); + + base::OnceClosure connected_callback_ GUARDED_BY_CONTEXT(sequence_checker_); + + base::OnceClosure disconnected_callback_ + GUARDED_BY_CONTEXT(sequence_checker_); + + std::unique_ptr<extensions::NativeMessageHost> native_message_host_ + GUARDED_BY_CONTEXT(sequence_checker_); + + mojo::Remote<mojom::SupportHostObserver> remote_ + GUARDED_BY_CONTEXT(sequence_checker_); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_IT2ME_IT2ME_NATIVE_MESSAGING_HOST_ASH_H_
diff --git a/remoting/host/it2me/it2me_native_messaging_host_lacros.cc b/remoting/host/it2me/it2me_native_messaging_host_lacros.cc index a242356..c00cf9c 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_lacros.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_lacros.cc
@@ -4,19 +4,426 @@ #include "remoting/host/it2me/it2me_native_messaging_host_lacros.h" -#include <memory> +#include <stddef.h> +#include <map> +#include <memory> +#include <string> + +#include "base/bind.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/memory/weak_ptr.h" #include "base/notreached.h" +#include "base/sequence_checker.h" +#include "base/single_thread_task_runner.h" +#include "base/time/time.h" +#include "base/values.h" +#include "chromeos/crosapi/mojom/remoting.mojom.h" +#include "chromeos/lacros/lacros_chrome_service_impl.h" +#include "extensions/browser/api/messaging/native_message_host.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "remoting/host/it2me/it2me_constants.h" +#include "remoting/host/it2me/it2me_helpers.h" +#include "remoting/host/mojom/remote_support.mojom.h" +#include "remoting/protocol/errors.h" namespace remoting { +namespace { + +constexpr int kInvalidMessageId = -1; + +int GetMessageId(const base::Value& message) { + const auto* message_id = message.FindPath(kMessageId); + return message_id ? message_id->GetInt() : kInvalidMessageId; +} + +protocol::ErrorCode SupportSessionErrorToProtocolError( + mojom::StartSupportSessionError session_error) { + switch (session_error) { + case mojom::StartSupportSessionError::kExistingAdminSession: + return protocol::ErrorCode::EXISTING_ADMIN_SESSION; + default: + return protocol::ErrorCode::UNKNOWN_ERROR; + } +} + +// This class is JSON <-> Mojo message converter which enables communication +// between a Chrome Remote Desktop (CRD) client website instance running in +// Lacros and the CRD components running in Ash. This class should not contain +// any logic beyond message processing, validation, and conversion. +// All interactions with it must occur on the sequence it was created on. +class It2MeNativeMessagingHostLacros : public extensions::NativeMessageHost, + public mojom::SupportHostObserver { + public: + explicit It2MeNativeMessagingHostLacros( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + ~It2MeNativeMessagingHostLacros() override; + + // extensions::NativeMessageHost implementation. + void OnMessage(const std::string& message) override; + void Start(Client* client) override; + scoped_refptr<base::SingleThreadTaskRunner> task_runner() const override; + + // mojom::SupportHostObserver implementation. + void OnHostStateStarting() override; + void OnHostStateRequestedAccessCode() override; + void OnHostStateReceivedAccessCode(const std::string& access_code, + base::TimeDelta lifetime) override; + void OnHostStateConnecting() override; + void OnHostStateConnected(const std::string& remote_username) override; + void OnHostStateDisconnected() override; + void OnNatPolicyChanged(mojom::NatPolicyStatePtr policy_state) override; + void OnHostStateError(int64_t error_code) override; + void OnPolicyError() override; + void OnInvalidDomainError() override; + + // Handlers for Mojo responses received from Ash. + void OnSupportHostDetailsReceived(mojom::SupportHostDetailsPtr host_details); + void OnSupportSessionStarted(mojom::StartSupportSessionResponsePtr response); + + private: + void ProcessHello(); + void ProcessConnect(base::Value message); + void ProcessDisconnect(base::Value message); + void SendMessageToClient(base::Value message) const; + void SendErrorAndExit(const protocol::ErrorCode error_code, + int message_id = kInvalidMessageId) const; + + void HandleHostStateChange(It2MeHostState state); + + SEQUENCE_CHECKER(sequence_checker_); + + Client* client_ GUARDED_BY_CONTEXT(sequence_checker_) = nullptr; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + std::string access_code_; + base::TimeDelta access_code_lifetime_; + std::string remote_username_; + int connect_response_id_ = kInvalidMessageId; + + bool hello_response_pending_ GUARDED_BY_CONTEXT(sequence_checker_) = false; + mojom::SupportHostDetailsPtr host_details_ + GUARDED_BY_CONTEXT(sequence_checker_); + mojo::Receiver<mojom::SupportHostObserver> support_host_observer_ + GUARDED_BY_CONTEXT(sequence_checker_){this}; + + base::WeakPtrFactory<It2MeNativeMessagingHostLacros> weak_factory_ + GUARDED_BY_CONTEXT(sequence_checker_){this}; +}; + +It2MeNativeMessagingHostLacros::It2MeNativeMessagingHostLacros( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner) {} + +It2MeNativeMessagingHostLacros::~It2MeNativeMessagingHostLacros() = default; + +void It2MeNativeMessagingHostLacros::OnMessage(const std::string& message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + std::string type; + base::Value contents; + if (!ParseIt2MeNativeMessageJson(message, type, contents)) { + client_->CloseChannel(std::string()); + return; + } + + if (type.empty()) { + LOG(ERROR) << "'type' not found in request."; + SendErrorAndExit(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL); + return; + } + + if (type == kHelloMessage) { + ProcessHello(); + } else if (type == kConnectMessage) { + ProcessConnect(std::move(contents)); + } else if (type == kDisconnectMessage) { + ProcessDisconnect(std::move(contents)); + } else { + LOG(ERROR) << "Unsupported request type: " << type; + SendErrorAndExit(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL); + } +} + +void It2MeNativeMessagingHostLacros::Start(Client* client) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + client_ = client; + + auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get(); + if (!lacros_chrome_service->IsAvailable<crosapi::mojom::Remoting>()) { + LOG(ERROR) << "Remoting is not available in this version of the browser."; + client_->CloseChannel(std::string()); + return; + } + + lacros_chrome_service->GetRemote<crosapi::mojom::Remoting>() + ->GetSupportHostDetails(base::BindOnce( + &It2MeNativeMessagingHostLacros::OnSupportHostDetailsReceived, + weak_factory_.GetWeakPtr())); +} + +scoped_refptr<base::SingleThreadTaskRunner> +It2MeNativeMessagingHostLacros::task_runner() const { + return task_runner_; +} + +void It2MeNativeMessagingHostLacros::OnHostStateStarting() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + HandleHostStateChange(It2MeHostState::kStarting); +} + +void It2MeNativeMessagingHostLacros::OnHostStateRequestedAccessCode() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + HandleHostStateChange(It2MeHostState::kRequestedAccessCode); +} + +void It2MeNativeMessagingHostLacros::OnHostStateReceivedAccessCode( + const std::string& access_code, + base::TimeDelta lifetime) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + access_code_ = access_code; + access_code_lifetime_ = lifetime; + HandleHostStateChange(It2MeHostState::kReceivedAccessCode); +} + +void It2MeNativeMessagingHostLacros::OnHostStateConnecting() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + HandleHostStateChange(It2MeHostState::kConnecting); +} + +void It2MeNativeMessagingHostLacros::OnHostStateConnected( + const std::string& remote_username) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + remote_username_ = remote_username; + HandleHostStateChange(It2MeHostState::kConnected); +} + +void It2MeNativeMessagingHostLacros::OnHostStateDisconnected() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + HandleHostStateChange(It2MeHostState::kDisconnected); +} + +void It2MeNativeMessagingHostLacros::OnNatPolicyChanged( + mojom::NatPolicyStatePtr policy_state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey(kMessageType, kNatPolicyChangedMessage); + message.SetBoolKey(kNatPolicyChangedMessageNatEnabled, + policy_state->nat_enabled); + message.SetBoolKey(kNatPolicyChangedMessageRelayEnabled, + policy_state->relay_enabled); + SendMessageToClient(std::move(message)); +} + +void It2MeNativeMessagingHostLacros::OnHostStateError(int64_t error_code) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GE(error_code, 0); + LOG_IF(WARNING, error_code >= protocol::ErrorCode::ERROR_CODE_MAX) + << "|error_code| is greater than the max known error_code."; + SendErrorAndExit(static_cast<protocol::ErrorCode>(error_code)); +} + +void It2MeNativeMessagingHostLacros::OnPolicyError() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value response(base::Value::Type::DICTIONARY); + response.SetStringKey(kMessageType, kPolicyErrorMessage); + SendMessageToClient(std::move(response)); + client_->CloseChannel(std::string()); +} + +void It2MeNativeMessagingHostLacros::OnInvalidDomainError() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + HandleHostStateChange(It2MeHostState::kInvalidDomainError); +} + +void It2MeNativeMessagingHostLacros::HandleHostStateChange( + It2MeHostState state) { + base::Value message(base::Value::Type::DICTIONARY); + message.SetStringKey(kMessageType, kHostStateChangedMessage); + + switch (state) { + case It2MeHostState::kStarting: + message.SetStringKey(kState, kHostStateStarting); + break; + + case It2MeHostState::kRequestedAccessCode: + message.SetStringKey(kState, kHostStateRequestedAccessCode); + break; + + case It2MeHostState::kReceivedAccessCode: + message.SetStringKey(kState, kHostStateReceivedAccessCode); + message.SetStringKey(kAccessCode, access_code_); + message.SetIntKey(kAccessCodeLifetime, access_code_lifetime_.InSeconds()); + break; + + case It2MeHostState::kConnecting: + message.SetStringKey(kState, kHostStateConnecting); + break; + + case It2MeHostState::kConnected: + message.SetStringKey(kState, kHostStateConnected); + message.SetStringKey(kClient, remote_username_); + break; + + case It2MeHostState::kDisconnected: + message.SetStringKey(kState, kHostStateDisconnected); + remote_username_.clear(); + break; + + case It2MeHostState::kInvalidDomainError: + message.SetStringKey(kState, kHostStateDomainError); + break; + + default: + NOTREACHED(); + break; + } + + SendMessageToClient(std::move(message)); +} + +void It2MeNativeMessagingHostLacros::OnSupportHostDetailsReceived( + mojom::SupportHostDetailsPtr host_details) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + host_details_ = std::move(host_details); + + if (hello_response_pending_) { + hello_response_pending_ = false; + ProcessHello(); + } +} + +void It2MeNativeMessagingHostLacros::OnSupportSessionStarted( + mojom::StartSupportSessionResponsePtr mojo_response) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (mojo_response->is_support_session_error()) { + SendErrorAndExit(SupportSessionErrorToProtocolError( + mojo_response->get_support_session_error()), + connect_response_id_); + return; + } + + support_host_observer_.Bind(std::move(mojo_response->get_observer())); + + base::Value response(base::Value::Type::DICTIONARY); + response.SetStringKey(kMessageType, kConnectResponse); + + if (connect_response_id_ != kInvalidMessageId) { + response.SetIntKey(kMessageId, connect_response_id_); + connect_response_id_ = kInvalidMessageId; + } + + SendMessageToClient(std::move(response)); +} + +void It2MeNativeMessagingHostLacros::ProcessHello() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (host_details_.is_null()) { + // We haven't received the host details from ash so wait before responding. + hello_response_pending_ = true; + return; + } + + base::Value response(base::Value::Type::DICTIONARY); + response.SetStringKey(kMessageType, kHelloResponse); + response.SetStringKey(kHostVersion, host_details_.get()->host_version); + + std::vector<base::Value> features; + for (const auto& feature : host_details_.get()->supported_features) { + features.emplace_back(base::Value(feature)); + } + response.SetKey(kSupportedFeatures, base::Value(std::move(features))); + SendMessageToClient(std::move(response)); +} + +void It2MeNativeMessagingHostLacros::ProcessConnect(base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + int message_id = GetMessageId(message); + if (message_id != kInvalidMessageId) { + connect_response_id_ = message_id; + } + + mojom::SupportSessionParamsPtr session_params = + mojom::SupportSessionParams::New(); + + std::string* user_name = message.FindStringKey(kUserName); + if (!user_name) { + SendErrorAndExit(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL, message_id); + return; + } + session_params->user_name = *user_name; + + std::string* access_token = message.FindStringKey(kAuthServiceWithToken); + if (!access_token) { + SendErrorAndExit(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL, message_id); + return; + } + session_params->oauth_access_token = *access_token; + + // TODO(joedow): Add the ability to toggle the RemoteCommand settings for + // testing purposes. This should probably be encapsulated in a check that the + // machine is in developer-mode and/or !NDEBUG. + + auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get(); + lacros_chrome_service->GetRemote<crosapi::mojom::Remoting>() + ->StartSupportSession( + std::move(session_params), + base::BindOnce( + &It2MeNativeMessagingHostLacros::OnSupportSessionStarted, + base::Unretained(this))); +} + +void It2MeNativeMessagingHostLacros::ProcessDisconnect(base::Value message) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + support_host_observer_.reset(); + + base::Value response(base::Value::Type::DICTIONARY); + response.SetStringKey(kMessageType, kDisconnectResponse); + int message_id = GetMessageId(message); + if (message_id != kInvalidMessageId) { + response.SetIntKey(kMessageId, message_id); + } + SendMessageToClient(std::move(response)); +} + +void It2MeNativeMessagingHostLacros::SendMessageToClient( + base::Value message) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + std::string message_json; + base::JSONWriter::Write(message, &message_json); + client_->PostMessageFromNativeHost(message_json); +} + +void It2MeNativeMessagingHostLacros::SendErrorAndExit( + const protocol::ErrorCode error_code, + int message_id) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::Value message(base::Value::Type::DICTIONARY); + + message.SetStringKey(kMessageType, kErrorMessage); + if (message_id != kInvalidMessageId) { + message.SetIntKey(kMessageId, message_id); + } + message.SetStringKey(kErrorMessageCode, ErrorCodeToString(error_code)); + message.SetStringKey(kErrorMessageDescription, ErrorCodeToString(error_code)); + + SendMessageToClient(std::move(message)); + + // Trigger a host shutdown by sending an empty message. + client_->CloseChannel(std::string()); +} + +} // namespace + std::unique_ptr<extensions::NativeMessageHost> CreateIt2MeNativeMessagingHostForLacros( scoped_refptr<base::SingleThreadTaskRunner> io_runnner, scoped_refptr<base::SingleThreadTaskRunner> ui_runnner) { - // TODO(joedow): Implement a remote support host for LaCrOS. - NOTIMPLEMENTED(); - return nullptr; + // TODO(joedow): Verify |io_runner| is not required then remove it. + return std::make_unique<It2MeNativeMessagingHostLacros>(ui_runnner); } } // namespace remoting
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc index 42dc9cb..a45d457 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -31,6 +31,7 @@ #include "remoting/base/auto_thread_task_runner.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/it2me/it2me_constants.h" +#include "remoting/host/it2me/it2me_helpers.h" #include "remoting/host/native_messaging/log_message_handler.h" #include "remoting/host/native_messaging/native_messaging_pipe.h" #include "remoting/host/native_messaging/pipe_messaging_channel.h" @@ -159,22 +160,22 @@ OnPolicyUpdate(std::move(policies)); - RunSetState(kStarting); - RunSetState(kRequestedAccessCode); + RunSetState(It2MeHostState::kStarting); + RunSetState(It2MeHostState::kRequestedAccessCode); host_context()->ui_task_runner()->PostTask( FROM_HERE, base::BindOnce(&It2MeHost::Observer::OnStoreAccessCode, observer_, kTestAccessCode, kTestAccessCodeLifetime)); - RunSetState(kReceivedAccessCode); - RunSetState(kConnecting); + RunSetState(It2MeHostState::kReceivedAccessCode); + RunSetState(It2MeHostState::kConnecting); host_context()->ui_task_runner()->PostTask( FROM_HERE, base::BindOnce(&It2MeHost::Observer::OnClientAuthenticated, observer_, kTestClientUsername)); - RunSetState(kConnected); + RunSetState(It2MeHostState::kConnected); } void MockIt2MeHost::Disconnect() { @@ -189,7 +190,7 @@ register_request_.reset(); signal_strategy_.reset(); - RunSetState(kDisconnected); + RunSetState(It2MeHostState::kDisconnected); } void MockIt2MeHost::CreateConnectionContextOnNetworkThread( @@ -442,15 +443,15 @@ ASSERT_TRUE(response->GetString(kState, &state)); std::string value; - if (state == It2MeNativeMessagingHost::HostStateToString(kStarting)) { + if (state == It2MeHostStateToString(It2MeHostState::kStarting)) { EXPECT_FALSE(starting_received); starting_received = true; - } else if (state == It2MeNativeMessagingHost::HostStateToString( - kRequestedAccessCode)) { + } else if (state == + It2MeHostStateToString(It2MeHostState::kRequestedAccessCode)) { EXPECT_FALSE(requestedAccessCode_received); requestedAccessCode_received = true; - } else if (state == It2MeNativeMessagingHost::HostStateToString( - kReceivedAccessCode)) { + } else if (state == + It2MeHostStateToString(It2MeHostState::kReceivedAccessCode)) { EXPECT_FALSE(receivedAccessCode_received); receivedAccessCode_received = true; @@ -461,12 +462,10 @@ EXPECT_TRUE( response->GetInteger(kAccessCodeLifetime, &access_code_lifetime)); EXPECT_EQ(kTestAccessCodeLifetime.InSeconds(), access_code_lifetime); - } else if (state == - It2MeNativeMessagingHost::HostStateToString(kConnecting)) { + } else if (state == It2MeHostStateToString(It2MeHostState::kConnecting)) { EXPECT_FALSE(connecting_received); connecting_received = true; - } else if (state == - It2MeNativeMessagingHost::HostStateToString(kConnected)) { + } else if (state == It2MeHostStateToString(It2MeHostState::kConnected)) { EXPECT_FALSE(connected_received); connected_received = true; @@ -501,7 +500,7 @@ } else if (type == kHostStateChangedMessage) { std::string state; ASSERT_TRUE(response->GetString(kState, &state)); - if (state == It2MeNativeMessagingHost::HostStateToString(kDisconnected)) { + if (state == It2MeHostStateToString(It2MeHostState::kDisconnected)) { EXPECT_FALSE(disconnected_received); disconnected_received = true; } else {
diff --git a/remoting/host/mojom/BUILD.gn b/remoting/host/mojom/BUILD.gn index ca9d08b..c87bdc64 100644 --- a/remoting/host/mojom/BUILD.gn +++ b/remoting/host/mojom/BUILD.gn
@@ -5,6 +5,13 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("mojom") { - sources = [ "remote_url_opener.mojom" ] - public_deps = [ "//url/mojom:url_mojom_gurl" ] + sources = [ + "remote_support.mojom", + "remote_url_opener.mojom", + ] + + deps = [ + "//mojo/public/mojom/base", + "//url/mojom:url_mojom_gurl", + ] }
diff --git a/remoting/host/mojom/remote_support.mojom b/remoting/host/mojom/remote_support.mojom new file mode 100644 index 0000000..0ea80f8 --- /dev/null +++ b/remoting/host/mojom/remote_support.mojom
@@ -0,0 +1,122 @@ +// 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 remoting.mojom; + +import "mojo/public/mojom/base/time.mojom"; + +[Stable] +struct SupportHostDetails { + // Version of the remote support host in major.minor.build.revision format. + // This is an opaque string which is parsed by the website client. + string host_version; + + // The set of features supported by the remote support host. This is + // an opaque set of strings which is parsed by the website client. + array<string> supported_features; +}; + +// Response to a StartSupportSession request. This union includes a support host +// observer if the session was started successfully, otherwise it includes an +// error reason to indicate why it failed. +[Stable] +union StartSupportSessionResponse { + // Used to observe connection state change events when a session was started + // successfully. + pending_receiver<remoting.mojom.SupportHostObserver> observer; + + // Provides the reason the session was not started. + remoting.mojom.StartSupportSessionError support_session_error; +}; + +// Provides the reason a remote support session could not be started. +[Stable, Extensible] +enum StartSupportSessionError { + [Default] kUnknown = 0, + + // The managed device admin has an existing connection which cannot be + // disconnected. + kExistingAdminSession = 1, +}; + +// The parameters required to start a remote support session. +[Stable] +struct SupportSessionParams { + // Gaia username of the user requesting the connection. + string user_name; + + // The access token used for connecting to signaling and CRD backend services. + string oauth_access_token; + + // Do not prompt local user for approval when connecting. Used for Admin + // initiated connections using the RemoteCommand infrastructure. + [EnableIf=is_chromeos] + bool suppress_user_dialogs; + + // Do not show connection notifications in the system tray. Used for Admin + // initiated connections using the RemoteCommand infrastructure. + [EnableIf=is_chromeos] + bool suppress_notifications; + + // Terminate the session if local user input is received. Used for Admin + // initiated connections using the RemoteCommand infrastructure. + [EnableIf=is_chromeos] + bool terminate_upon_input; +}; + +// Represents the state of the remote support host NAT device policies. +[Stable] +struct NatPolicyState { + // Indicates whether NAT traversal is enabled. + bool nat_enabled; + + // Indicates whether TURN (relay) connections are allowed. Note that this + // value is only considered for P2P connection establishment when + // |nat_enabled| is true. + bool relay_enabled; +}; + +// Used by the remote support host to provides connection state change and error +// events to the owner of the remote support session. This is typically the +// native message host which is owned by the CRD client website. +// This is currently only implemented on CrOS, where the remote for this +// interface is owned in ash-chrome and the receiver is bound in lacros-chrome. +[Stable, Uuid="3961f91c-dd8f-4b9b-a6ae-6bf8371d5a91"] +interface SupportHostObserver { + // Indicates the remote support host is starting. + OnHostStateStarting@0(); + + // Indicates the remote support host has requested an access code. + OnHostStateRequestedAccessCode@1(); + + // Indicates the remote support host has received an access code. + // |access_code| is an opaque string (12 digit code) which is provided to the + // remote user who uses it to connect to this session. + // |lifetime| is the amount of time |access_code| is valid. + OnHostStateReceivedAccessCode@2(string access_code, + mojo_base.mojom.TimeDelta lifetime); + + // Indicates the remote support host is beginning the connection process. + OnHostStateConnecting@3(); + + // Indicates the remote support host has completed the connection process. + // |remote_user_address| is the Gaia address of the remote user. + OnHostStateConnected@4(string remote_username); + + // Indicates the remote support host is now disconnected. + OnHostStateDisconnected@6(); + + // Indicates there was a change to the NAT device policy. + OnNatPolicyChanged@7(NatPolicyState nat_policy_state); + + // Indicates the host experienced an unexpected error. + OnHostStateError@8(int64 error_code); + + // Indicates the host experienced an error loading the device policy. + OnPolicyError@9(); + + // Indicates the remote support host could not start as the user's domain is + // not included in the device policy allowlist. + OnInvalidDomainError@10(); +};
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn index a02f48f3..d8d8e8d 100644 --- a/remoting/protocol/BUILD.gn +++ b/remoting/protocol/BUILD.gn
@@ -6,6 +6,14 @@ import("//media/media_options.gni") import("//remoting/remoting_options.gni") +static_library("errors") { + sources = [ + "errors.cc", + "errors.h", + ] + deps = [ "//remoting/base:base" ] +} + static_library("protocol") { sources = [ "audio_decode_scheduler.cc", @@ -58,8 +66,6 @@ "datagram_channel_factory.h", "display_size.cc", "display_size.h", - "errors.cc", - "errors.h", "file_transfer_helpers.cc", "file_transfer_helpers.h", "frame_consumer.h", @@ -216,6 +222,7 @@ ] public_deps = [ + ":errors", ":session_config", "//remoting/proto", "//third_party/webrtc_overrides:webrtc_component",
diff --git a/remoting/protocol/errors.h b/remoting/protocol/errors.h index b21d9d6..55aae27 100644 --- a/remoting/protocol/errors.h +++ b/remoting/protocol/errors.h
@@ -32,6 +32,7 @@ ELEVATION_ERROR, HOST_CERTIFICATE_ERROR, HOST_REGISTRATION_ERROR, + EXISTING_ADMIN_SESSION, ERROR_CODE_MAX = UNKNOWN_ERROR, };
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc index 05c39f0..086c56a2 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -178,6 +178,12 @@ return RestrictCloneToThreadsAndEPERMFork(); } + // clone3 takes a pointer argument which we cannot examine, so return ENOSYS + // to force the libc to use clone. See https://crbug.com/1213452. + if (sysno == __NR_clone3) { + return Error(ENOSYS); + } + if (sysno == __NR_fcntl) return RestrictFcntlCommands();
diff --git a/sandbox/linux/system_headers/arm64_linux_syscalls.h b/sandbox/linux/system_headers/arm64_linux_syscalls.h index a242c18c..ab86b36 100644 --- a/sandbox/linux/system_headers/arm64_linux_syscalls.h +++ b/sandbox/linux/system_headers/arm64_linux_syscalls.h
@@ -1119,4 +1119,100 @@ #define __NR_rseq 293 #endif +#if !defined(__NR_kexec_file_load) +#define __NR_kexec_file_load 294 +#endif + +#if !defined(__NR_pidfd_send_signal) +#define __NR_pidfd_send_signal 424 +#endif + +#if !defined(__NR_io_uring_setup) +#define __NR_io_uring_setup 425 +#endif + +#if !defined(__NR_io_uring_enter) +#define __NR_io_uring_enter 426 +#endif + +#if !defined(__NR_io_uring_register) +#define __NR_io_uring_register 427 +#endif + +#if !defined(__NR_open_tree) +#define __NR_open_tree 428 +#endif + +#if !defined(__NR_move_mount) +#define __NR_move_mount 429 +#endif + +#if !defined(__NR_fsopen) +#define __NR_fsopen 430 +#endif + +#if !defined(__NR_fsconfig) +#define __NR_fsconfig 431 +#endif + +#if !defined(__NR_fsmount) +#define __NR_fsmount 432 +#endif + +#if !defined(__NR_fspick) +#define __NR_fspick 433 +#endif + +#if !defined(__NR_pidfd_open) +#define __NR_pidfd_open 434 +#endif + +#if !defined(__NR_clone3) +#define __NR_clone3 435 +#endif + +#if !defined(__NR_close_range) +#define __NR_close_range 436 +#endif + +#if !defined(__NR_openat2) +#define __NR_openat2 437 +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd 438 +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 439 +#endif + +#if !defined(__NR_process_madvise) +#define __NR_process_madvise 440 +#endif + +#if !defined(__NR_epoll_pwait2) +#define __NR_epoll_pwait2 441 +#endif + +#if !defined(__NR_mount_setattr) +#define __NR_mount_setattr 442 +#endif + +#if !defined(__NR_quotactl_path) +#define __NR_quotactl_path 443 +#endif + +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset 444 +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule 445 +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self 446 +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/arm_linux_syscalls.h b/sandbox/linux/system_headers/arm_linux_syscalls.h index 85da6f4..9c44368 100644 --- a/sandbox/linux/system_headers/arm_linux_syscalls.h +++ b/sandbox/linux/system_headers/arm_linux_syscalls.h
@@ -1605,6 +1605,18 @@ #define __NR_mount_setattr (__NR_SYSCALL_BASE + 442) #endif +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset (__NR_SYSCALL_BASE + 444) +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule (__NR_SYSCALL_BASE + 445) +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self (__NR_SYSCALL_BASE + 446) +#endif + // ARM private syscalls. #if !defined(__ARM_NR_BASE) #define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000)
diff --git a/sandbox/linux/system_headers/mips64_linux_syscalls.h b/sandbox/linux/system_headers/mips64_linux_syscalls.h index ec75815a..ae7cb48 100644 --- a/sandbox/linux/system_headers/mips64_linux_syscalls.h +++ b/sandbox/linux/system_headers/mips64_linux_syscalls.h
@@ -1271,4 +1271,148 @@ #define __NR_memfd_create (__NR_Linux + 314) #endif +#if !defined(__NR_bpf) +#define __NR_bpf (__NR_Linux + 315) +#endif + +#if !defined(__NR_execveat) +#define __NR_execveat (__NR_Linux + 316) +#endif + +#if !defined(__NR_userfaultfd) +#define __NR_userfaultfd (__NR_Linux + 317) +#endif + +#if !defined(__NR_membarrier) +#define __NR_membarrier (__NR_Linux + 318) +#endif + +#if !defined(__NR_mlock2) +#define __NR_mlock2 (__NR_Linux + 319) +#endif + +#if !defined(__NR_copy_file_range) +#define __NR_copy_file_range (__NR_Linux + 320) +#endif + +#if !defined(__NR_preadv2) +#define __NR_preadv2 (__NR_Linux + 321) +#endif + +#if !defined(__NR_pwritev2) +#define __NR_pwritev2 (__NR_Linux + 322) +#endif + +#if !defined(__NR_pkey_mprotect) +#define __NR_pkey_mprotect (__NR_Linux + 323) +#endif + +#if !defined(__NR_pkey_alloc) +#define __NR_pkey_alloc (__NR_Linux + 324) +#endif + +#if !defined(__NR_pkey_free) +#define __NR_pkey_free (__NR_Linux + 325) +#endif + +#if !defined(__NR_statx) +#define __NR_statx (__NR_Linux + 326) +#endif + +#if !defined(__NR_rseq) +#define __NR_rseq (__NR_Linux + 327) +#endif + +#if !defined(__NR_io_pgetevents) +#define __NR_io_pgetevents (__NR_Linux + 328) +#endif + +#if !defined(__NR_pidfd_send_signal) +#define __NR_pidfd_send_signal (__NR_Linux + 424) +#endif + +#if !defined(__NR_io_uring_setup) +#define __NR_io_uring_setup (__NR_Linux + 425) +#endif + +#if !defined(__NR_io_uring_enter) +#define __NR_io_uring_enter (__NR_Linux + 426) +#endif + +#if !defined(__NR_io_uring_register) +#define __NR_io_uring_register (__NR_Linux + 427) +#endif + +#if !defined(__NR_open_tree) +#define __NR_open_tree (__NR_Linux + 428) +#endif + +#if !defined(__NR_move_mount) +#define __NR_move_mount (__NR_Linux + 429) +#endif + +#if !defined(__NR_fsopen) +#define __NR_fsopen (__NR_Linux + 430) +#endif + +#if !defined(__NR_fsconfig) +#define __NR_fsconfig (__NR_Linux + 431) +#endif + +#if !defined(__NR_fsmount) +#define __NR_fsmount (__NR_Linux + 432) +#endif + +#if !defined(__NR_fspick) +#define __NR_fspick (__NR_Linux + 433) +#endif + +#if !defined(__NR_pidfd_open) +#define __NR_pidfd_open (__NR_Linux + 434) +#endif + +#if !defined(__NR_clone3) +#define __NR_clone3 (__NR_Linux + 435) +#endif + +#if !defined(__NR_close_range) +#define __NR_close_range (__NR_Linux + 436) +#endif + +#if !defined(__NR_openat2) +#define __NR_openat2 (__NR_Linux + 437) +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd (__NR_Linux + 438) +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 (__NR_Linux + 439) +#endif + +#if !defined(__NR_process_madvise) +#define __NR_process_madvise (__NR_Linux + 440) +#endif + +#if !defined(__NR_epoll_pwait2) +#define __NR_epoll_pwait2 (__NR_Linux + 441) +#endif + +#if !defined(__NR_mount_setattr) +#define __NR_mount_setattr (__NR_Linux + 442) +#endif + +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset (__NR_Linux + 444) +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule (__NR_Linux + 445) +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self (__NR_Linux + 446) +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/mips_linux_syscalls.h b/sandbox/linux/system_headers/mips_linux_syscalls.h index 50d9ea1..0937782 100644 --- a/sandbox/linux/system_headers/mips_linux_syscalls.h +++ b/sandbox/linux/system_headers/mips_linux_syscalls.h
@@ -1685,4 +1685,16 @@ #define __NR_mount_setattr (__NR_Linux + 442) #endif +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset (__NR_Linux + 444) +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule (__NR_Linux + 445) +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self (__NR_Linux + 446) +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/sandbox/linux/system_headers/x86_32_linux_syscalls.h index 1720edb..2c81a930 100644 --- a/sandbox/linux/system_headers/x86_32_linux_syscalls.h +++ b/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -1738,5 +1738,17 @@ #define __NR_mount_setattr 442 #endif +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset 444 +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule 445 +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self 446 +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/sandbox/linux/system_headers/x86_64_linux_syscalls.h index b0ae0a2..e618c62 100644 --- a/sandbox/linux/system_headers/x86_64_linux_syscalls.h +++ b/sandbox/linux/system_headers/x86_64_linux_syscalls.h
@@ -1350,5 +1350,93 @@ #define __NR_rseq 334 #endif +#if !defined(__NR_pidfd_send_signal) +#define __NR_pidfd_send_signal 424 +#endif + +#if !defined(__NR_io_uring_setup) +#define __NR_io_uring_setup 425 +#endif + +#if !defined(__NR_io_uring_enter) +#define __NR_io_uring_enter 426 +#endif + +#if !defined(__NR_io_uring_register) +#define __NR_io_uring_register 427 +#endif + +#if !defined(__NR_open_tree) +#define __NR_open_tree 428 +#endif + +#if !defined(__NR_move_mount) +#define __NR_move_mount 429 +#endif + +#if !defined(__NR_fsopen) +#define __NR_fsopen 430 +#endif + +#if !defined(__NR_fsconfig) +#define __NR_fsconfig 431 +#endif + +#if !defined(__NR_fsmount) +#define __NR_fsmount 432 +#endif + +#if !defined(__NR_fspick) +#define __NR_fspick 433 +#endif + +#if !defined(__NR_pidfd_open) +#define __NR_pidfd_open 434 +#endif + +#if !defined(__NR_clone3) +#define __NR_clone3 435 +#endif + +#if !defined(__NR_close_range) +#define __NR_close_range 436 +#endif + +#if !defined(__NR_openat2) +#define __NR_openat2 437 +#endif + +#if !defined(__NR_pidfd_getfd) +#define __NR_pidfd_getfd 438 +#endif + +#if !defined(__NR_faccessat2) +#define __NR_faccessat2 439 +#endif + +#if !defined(__NR_process_madvise) +#define __NR_process_madvise 440 +#endif + +#if !defined(__NR_epoll_pwait2) +#define __NR_epoll_pwait2 441 +#endif + +#if !defined(__NR_mount_setattr) +#define __NR_mount_setattr 442 +#endif + +#if !defined(__NR_landlock_create_ruleset) +#define __NR_landlock_create_ruleset 444 +#endif + +#if !defined(__NR_landlock_add_rule) +#define __NR_landlock_add_rule 445 +#endif + +#if !defined(__NR_landlock_restrict_self) +#define __NR_landlock_restrict_self 446 +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
diff --git a/services/network/cookie_settings.cc b/services/network/cookie_settings.cc index 3e0c5b6..fe81960 100644 --- a/services/network/cookie_settings.cc +++ b/services/network/cookie_settings.cc
@@ -191,11 +191,9 @@ } bool CookieSettings::HasSessionOnlyOrigins() const { - for (const auto& entry : content_settings_) { - if (entry.GetContentSetting() == CONTENT_SETTING_SESSION_ONLY) - return true; - } - return false; + return base::ranges::any_of(content_settings_, [](const auto& entry) { + return entry.GetContentSetting() == CONTENT_SETTING_SESSION_ONLY; + }); } } // namespace network
diff --git a/services/network/trust_tokens/BUILD.gn b/services/network/trust_tokens/BUILD.gn index ce25b0a..8a765ca 100644 --- a/services/network/trust_tokens/BUILD.gn +++ b/services/network/trust_tokens/BUILD.gn
@@ -20,6 +20,10 @@ "boringssl_trust_token_issuance_cryptographer.h", "boringssl_trust_token_redemption_cryptographer.cc", "boringssl_trust_token_redemption_cryptographer.h", + "ecdsa_p256_key_pair_generator.cc", + "ecdsa_p256_key_pair_generator.h", + "ecdsa_sha256_trust_token_request_signer.cc", + "ecdsa_sha256_trust_token_request_signer.h", "ed25519_key_pair_generator.cc", "ed25519_key_pair_generator.h", "ed25519_trust_token_request_signer.cc", @@ -132,8 +136,8 @@ sources = [ "boringssl_trust_token_issuance_cryptographer_unittest.cc", + "ecdsa_p256_key_pair_generator_unittest.cc", "ed25519_key_pair_generator_unittest.cc", - "ed25519_trust_token_request_signer_unittest.cc", "expiry_inspecting_record_expiry_delegate_unittest.cc", "has_trust_tokens_answerer_unittest.cc", "local_trust_token_operation_delegate_impl_unittest.cc", @@ -153,6 +157,7 @@ "trust_token_request_helper_factory_unittest.cc", "trust_token_request_issuance_helper_unittest.cc", "trust_token_request_redemption_helper_unittest.cc", + "trust_token_request_signer_unittest.cc", "trust_token_request_signing_helper_unittest.cc", "trust_token_store_unittest.cc", "types_unittest.cc",
diff --git a/services/network/trust_tokens/ecdsa_p256_key_pair_generator.cc b/services/network/trust_tokens/ecdsa_p256_key_pair_generator.cc new file mode 100644 index 0000000..cf679d7 --- /dev/null +++ b/services/network/trust_tokens/ecdsa_p256_key_pair_generator.cc
@@ -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. + +#include "services/network/trust_tokens/ecdsa_p256_key_pair_generator.h" + +#include "crypto/ec_private_key.h" + +namespace network { + +bool EcdsaP256KeyPairGenerator::Generate(std::string* signing_key_out, + std::string* verification_key_out) { + std::unique_ptr<crypto::ECPrivateKey> key_pair = + crypto::ECPrivateKey::Create(); + std::vector<uint8_t> private_key; + std::string public_key; + if (!key_pair->ExportPrivateKey(&private_key)) { + return false; + } + if (!key_pair->ExportRawPublicKey(verification_key_out)) { + return false; + } + signing_key_out->assign(private_key.begin(), private_key.end()); + + return true; +} + +} // namespace network
diff --git a/services/network/trust_tokens/ecdsa_p256_key_pair_generator.h b/services/network/trust_tokens/ecdsa_p256_key_pair_generator.h new file mode 100644 index 0000000..7776c4d --- /dev/null +++ b/services/network/trust_tokens/ecdsa_p256_key_pair_generator.h
@@ -0,0 +1,29 @@ +// 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 SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_ +#define SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_ + +#include "services/network/trust_tokens/trust_token_request_redemption_helper.h" + +namespace network { + +// EcdsaP256KeyPairGenerator generates an ECDSA key pair based on the NIST +// P-256 curve. The |verification_key_out| is encoded as an EC point in the +// uncompressed point format and the |signing_key_out| is encoded as a PKCS #8 +// PrivateKeyInfo block. +class EcdsaP256KeyPairGenerator + : public TrustTokenRequestRedemptionHelper::KeyPairGenerator { + public: + EcdsaP256KeyPairGenerator() = default; + ~EcdsaP256KeyPairGenerator() override = default; + + // TrustTokenRequestRedemptionHelper::KeyPairGenerator implementation: + bool Generate(std::string* signing_key_out, + std::string* verification_key_out) override; +}; + +} // namespace network + +#endif // SERVICES_NETWORK_TRUST_TOKENS_ECDSA_P256_KEY_PAIR_GENERATOR_H_
diff --git a/services/network/trust_tokens/ecdsa_p256_key_pair_generator_unittest.cc b/services/network/trust_tokens/ecdsa_p256_key_pair_generator_unittest.cc new file mode 100644 index 0000000..aa6c0a9 --- /dev/null +++ b/services/network/trust_tokens/ecdsa_p256_key_pair_generator_unittest.cc
@@ -0,0 +1,31 @@ +// 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 "services/network/trust_tokens/ecdsa_p256_key_pair_generator.h" +#include "base/containers/span.h" +#include "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace network { + +TEST(EcdsaP256KeyPairGenerator, Roundtrip) { + auto message = base::as_bytes(base::make_span( + "Four score and seven years ago our fathers brought forth on this " + "continent, a new nation, conceived in Liberty, and dedicated to the " + "proposition that all men are created equal.")); + + std::string signing, verification; + ASSERT_TRUE(EcdsaP256KeyPairGenerator().Generate(&signing, &verification)); + + EcdsaSha256TrustTokenRequestSigner signer; + + absl::optional<std::vector<uint8_t>> signature = + signer.Sign(base::as_bytes(base::make_span(signing)), message); + ASSERT_TRUE(signature); + + EXPECT_TRUE(signer.Verify(message, *signature, + base::as_bytes(base::make_span(verification)))); +} + +} // namespace network
diff --git a/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.cc b/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.cc new file mode 100644 index 0000000..aac3f682 --- /dev/null +++ b/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.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 "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h" + +#include "crypto/ec_private_key.h" +#include "crypto/ec_signature_creator.h" +#include "crypto/signature_verifier.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/ecdsa.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/mem.h" + +namespace network { + +EcdsaSha256TrustTokenRequestSigner::EcdsaSha256TrustTokenRequestSigner() = + default; +EcdsaSha256TrustTokenRequestSigner::~EcdsaSha256TrustTokenRequestSigner() = + default; + +absl::optional<std::vector<uint8_t>> EcdsaSha256TrustTokenRequestSigner::Sign( + base::span<const uint8_t> key, + base::span<const uint8_t> data) { + std::unique_ptr<crypto::ECPrivateKey> private_key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(key); + if (!private_key) + return absl::nullopt; + + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(private_key->key()); + if (!ec_key) + return absl::nullopt; + + if (EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != + NID_X9_62_prime256v1) + return absl::nullopt; + + std::unique_ptr<crypto::ECSignatureCreator> sig_creator = + crypto::ECSignatureCreator::Create(private_key.get()); + + std::vector<uint8_t> signature; + + if (!sig_creator->Sign(data.data(), data.size(), &signature)) + return absl::nullopt; + + return signature; +} + +bool EcdsaSha256TrustTokenRequestSigner::Verify( + base::span<const uint8_t> data, + base::span<const uint8_t> signature, + base::span<const uint8_t> verification_key) { + // Require the public key be in uncompressed form. EC_POINT_oct2point + // also accepts compressed form. + if (verification_key.empty() || + verification_key[0] != POINT_CONVERSION_UNCOMPRESSED) { + return false; + } + + bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(EC_KEY_get0_group(key.get()))); + if (!EC_POINT_oct2point(EC_KEY_get0_group(key.get()), pub_key.get(), + verification_key.data(), verification_key.size(), + nullptr) || + !EC_KEY_set_public_key(key.get(), pub_key.get())) { + return false; + } + + bssl::UniquePtr<EVP_PKEY> public_key(EVP_PKEY_new()); + if (!EVP_PKEY_set1_EC_KEY(public_key.get(), key.get())) { + return false; + } + + bssl::ScopedEVP_MD_CTX ctx; + EVP_PKEY_CTX* pctx; + if (!EVP_DigestVerifyInit(ctx.get(), &pctx, EVP_sha256(), nullptr, + public_key.get())) { + return false; + } + + return EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), + data.data(), data.size()); +} + +std::string EcdsaSha256TrustTokenRequestSigner::GetAlgorithmIdentifier() { + return "EcdsaSha256TrustTokenRequestSigner"; +} + +} // namespace network
diff --git a/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h b/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h new file mode 100644 index 0000000..8c7486e --- /dev/null +++ b/services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h
@@ -0,0 +1,36 @@ +// 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 SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_ +#define SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_ + +#include "services/network/trust_tokens/trust_token_request_signing_helper.h" + +namespace network { + +// EcdsaSha256TrustTokenRequestSigner provides a wrapper around BoringSSL's +// ECDSA signing and verification routines capable of satisfying the Trust +// Tokens signing request helper's Signer delegate interface. The signature is a +// DER encoded ECDSA-Sig-Value from RFC 3279. +class EcdsaSha256TrustTokenRequestSigner + : public TrustTokenRequestSigningHelper::Signer { + public: + EcdsaSha256TrustTokenRequestSigner(); + ~EcdsaSha256TrustTokenRequestSigner() override; + + // TrustTokenRequestSigningHelper::Signer implementation: + absl::optional<std::vector<uint8_t>> Sign( + base::span<const uint8_t> key, + base::span<const uint8_t> data) override; + + bool Verify(base::span<const uint8_t> data, + base::span<const uint8_t> signature, + base::span<const uint8_t> verification_key) override; + + std::string GetAlgorithmIdentifier() override; +}; + +} // namespace network + +#endif // SERVICES_NETWORK_TRUST_TOKENS_ECDSA_SHA256_TRUST_TOKEN_REQUEST_SIGNER_H_
diff --git a/services/network/trust_tokens/ed25519_trust_token_request_signer_unittest.cc b/services/network/trust_tokens/ed25519_trust_token_request_signer_unittest.cc deleted file mode 100644 index b55a005..0000000 --- a/services/network/trust_tokens/ed25519_trust_token_request_signer_unittest.cc +++ /dev/null
@@ -1,216 +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 "services/network/trust_tokens/ed25519_trust_token_request_signer.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/boringssl/src/include/openssl/curve25519.h" - -namespace network { - -namespace { - -struct Keys { - std::array<uint8_t, ED25519_PRIVATE_KEY_LEN> signing; - std::array<uint8_t, ED25519_PUBLIC_KEY_LEN> verification; -}; - -// The fixed constant 32 comes from curve25519.h and is not defined in a macro. -Keys KeysFromSeed(base::span<const uint8_t, 32> seed) { - Keys ret; - - // Cannot fail. - ED25519_keypair_from_seed(ret.verification.data(), ret.signing.data(), - seed.data()); - - return ret; -} - -const char kLongishMessage[] = - "Four score and seven years ago our fathers brought forth on this " - "continent, a new nation, conceived in Liberty, and dedicated to the " - "proposition that all men are created equal."; - -} // namespace - -TEST(Ed25519TrustTokenRequestSigner, Roundtrip) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - ASSERT_TRUE(signature); - - EXPECT_TRUE(signer.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, EmptyMessage) { - auto message = base::span<const uint8_t>(); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - ASSERT_TRUE(signature); - - EXPECT_TRUE(signer.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, ShortMessage) { - auto message = base::as_bytes(base::make_span("Hello")); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - ASSERT_TRUE(signature); - - EXPECT_TRUE(signer.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, LongerMessage) { - std::vector<uint8_t> message(1000000); - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - ASSERT_TRUE(signature); - - EXPECT_TRUE(signer.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, VerificationFromDifferentSigner) { - // Test that Verify works without prior initialization and signing, as its - // contract promises. - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - - Ed25519TrustTokenRequestSigner verifier; - EXPECT_TRUE(verifier.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, SigningKeyTooShort) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(base::make_span(keys.signing).subspan(1), message); - EXPECT_FALSE(signature); -} - -TEST(Ed25519TrustTokenRequestSigner, SigningKeyTooLong) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - Ed25519TrustTokenRequestSigner signer; - - std::vector<uint8_t> overlong_signing_key(ED25519_PRIVATE_KEY_LEN + 1); - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(overlong_signing_key, message); - EXPECT_FALSE(signature); -} - -TEST(Ed25519TrustTokenRequestSigner, VerificationKeyTooShort) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - - EXPECT_FALSE(signer.Verify(message, *signature, - base::make_span(keys.verification).subspan(1))); -} - -TEST(Ed25519TrustTokenRequestSigner, VerificationKeyTooLong) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - - std::vector<uint8_t> overlong_verification_key(ED25519_PUBLIC_KEY_LEN + 1); - - EXPECT_FALSE(signer.Verify(message, *signature, overlong_verification_key)); -} - -TEST(Ed25519TrustTokenRequestSigner, SignatureTooShort) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - signature->pop_back(); - - EXPECT_FALSE(signer.Verify(message, *signature, keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, SignatureTooLong) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - signature->push_back(0); - - EXPECT_FALSE( - signer.Verify(message, base::make_span(*signature), keys.verification)); -} - -TEST(Ed25519TrustTokenRequestSigner, SignatureWrong) { - auto message = base::as_bytes(base::make_span(kLongishMessage)); - - std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; - Keys keys = KeysFromSeed(seed); - - Ed25519TrustTokenRequestSigner signer; - - absl::optional<std::vector<uint8_t>> signature = - signer.Sign(keys.signing, message); - - // Corrupt the signature. - signature->front() += 1; - - EXPECT_FALSE(signer.Verify(message, *signature, keys.verification)); -} - -} // namespace network
diff --git a/services/network/trust_tokens/trust_token_request_signer_unittest.cc b/services/network/trust_tokens/trust_token_request_signer_unittest.cc new file mode 100644 index 0000000..5505b94 --- /dev/null +++ b/services/network/trust_tokens/trust_token_request_signer_unittest.cc
@@ -0,0 +1,282 @@ +// 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 "crypto/ec_private_key.h" +#include "services/network/trust_tokens/ecdsa_sha256_trust_token_request_signer.h" +#include "services/network/trust_tokens/ed25519_trust_token_request_signer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/boringssl/src/include/openssl/curve25519.h" + +namespace network { + +namespace { + +struct Keys { + std::vector<uint8_t> signing; + std::vector<uint8_t> verification; +}; + +const char kLongishMessage[] = + "Four score and seven years ago our fathers brought forth on this " + "continent, a new nation, conceived in Liberty, and dedicated to the " + "proposition that all men are created equal."; + +enum class RequestSigner { + kEd25519 = 0, + kEcdsaSha256 = 1, +}; + +} // namespace + +class TrustTokenRequestSigner : public ::testing::TestWithParam<RequestSigner> { + protected: + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> CreateSigner() { + switch (GetParam()) { + case RequestSigner::kEd25519: + return std::make_unique<Ed25519TrustTokenRequestSigner>(); + + case RequestSigner::kEcdsaSha256: + return std::make_unique<EcdsaSha256TrustTokenRequestSigner>(); + } + } + + // The fixed constant 32 comes from curve25519.h and is not defined in a + // macro. + Keys GetTestKeys() { + Keys ret; + switch (GetParam()) { + case RequestSigner::kEd25519: { + ret.signing.resize(ED25519_PRIVATE_KEY_LEN); + ret.verification.resize(ED25519_PUBLIC_KEY_LEN); + // Cannot fail. + std::array<uint8_t, 32> seed{1, 2, 3, 4, 5}; + ED25519_keypair_from_seed(ret.verification.data(), ret.signing.data(), + seed.data()); + break; + } + case RequestSigner::kEcdsaSha256: + const std::vector<uint8_t> private_key = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, + 0x01, 0x04, 0x20, 0x7f, 0x4c, 0x85, 0x5d, 0xcb, 0xd5, 0x3e, 0x9e, + 0xed, 0x0a, 0x34, 0xc9, 0xbf, 0xbc, 0xfb, 0x0e, 0xcd, 0xd8, 0xa0, + 0x89, 0x7e, 0x1d, 0xaf, 0x1c, 0x1e, 0x9f, 0x8c, 0x9f, 0xac, 0x21, + 0xee, 0xa5, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x62, 0x22, 0x44, + 0x4b, 0x41, 0x0e, 0x16, 0xcc, 0x6e, 0xbb, 0x72, 0xb9, 0xe5, 0x70, + 0xba, 0x13, 0xd0, 0xd2, 0x1f, 0x8f, 0x2a, 0x10, 0x57, 0x32, 0x77, + 0xb8, 0xd0, 0x62, 0x7e, 0x4d, 0x18, 0x6d, 0xc2, 0x87, 0x25, 0x17, + 0x45, 0x11, 0x82, 0xf2, 0x93, 0xed, 0xd5, 0x60, 0x7f, 0xae, 0x67, + 0x87, 0x39, 0x15, 0x90, 0x16, 0x91, 0x3c, 0xf9, 0x11, 0x76, 0x09, + 0xfa, 0x51, 0x90, 0xa4, 0x2f, 0x9a}; + std::unique_ptr<crypto::ECPrivateKey> key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(private_key); + std::vector<uint8_t> ec_private_key; + key->ExportPrivateKey(&ec_private_key); + ret.signing.swap(ec_private_key); + + std::string public_key; + key->ExportRawPublicKey(&public_key); + ret.verification = + std::vector<uint8_t>(public_key.begin(), public_key.end()); + std::string raw_public_key; + key->ExportRawPublicKey(&raw_public_key); + break; + } + return ret; + } +}; // namespace network + +TEST_P(TrustTokenRequestSigner, Roundtrip) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + ASSERT_TRUE(signature); + + EXPECT_TRUE(signer->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, EmptyMessage) { + auto message = base::span<const uint8_t>(); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + ASSERT_TRUE(signature); + + EXPECT_TRUE(signer->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, ShortMessage) { + auto message = base::as_bytes(base::make_span("Hello")); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + ASSERT_TRUE(signature); + + EXPECT_TRUE(signer->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, LongerMessage) { + std::vector<uint8_t> message(1000000); + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + ASSERT_TRUE(signature); + + EXPECT_TRUE(signer->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, VerificationFromDifferentSigner) { + // Test that Verify works without prior initialization and signing, as its + // contract promises. + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> verifier = + CreateSigner(); + EXPECT_TRUE(verifier->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, SigningKeyTooShort) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(base::make_span(keys.signing).subspan(1), message); + EXPECT_FALSE(signature); +} + +TEST_P(TrustTokenRequestSigner, SigningKeyTooLong) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + Keys keys = GetTestKeys(); + std::vector<uint8_t> overlong_signing_key(keys.signing.size() + 1); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(overlong_signing_key, message); + EXPECT_FALSE(signature); +} + +TEST_P(TrustTokenRequestSigner, VerificationKeyTooShort) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + + EXPECT_FALSE(signer->Verify(message, *signature, + base::make_span(keys.verification).subspan(1))); +} + +TEST_P(TrustTokenRequestSigner, VerificationKeyTooLong) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + + std::vector<uint8_t> overlong_verification_key(keys.verification.size() + 1); + + EXPECT_FALSE(signer->Verify(message, *signature, overlong_verification_key)); +} + +TEST_P(TrustTokenRequestSigner, SignatureTooShort) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + signature->pop_back(); + + EXPECT_FALSE(signer->Verify(message, *signature, keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, SignatureTooLong) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + signature->push_back(0); + + EXPECT_FALSE( + signer->Verify(message, base::make_span(*signature), keys.verification)); +} + +TEST_P(TrustTokenRequestSigner, SignatureWrong) { + auto message = base::as_bytes(base::make_span(kLongishMessage)); + + Keys keys = GetTestKeys(); + + std::unique_ptr<TrustTokenRequestSigningHelper::Signer> signer = + CreateSigner(); + + absl::optional<std::vector<uint8_t>> signature = + signer->Sign(keys.signing, message); + + // Corrupt the signature. + signature->front() += 1; + + EXPECT_FALSE(signer->Verify(message, *signature, keys.verification)); +} + +INSTANTIATE_TEST_SUITE_P( + Algorithm, + TrustTokenRequestSigner, + ::testing::Values(RequestSigner::kEd25519, RequestSigner::kEcdsaSha256), + [](const testing::TestParamInfo<TrustTokenRequestSigner::ParamType>& info) { + return info.param == RequestSigner::kEd25519 ? "ED25519" : "ECDSA_SHA256"; + }); + +} // namespace network
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc index eb65caf..6bf5540 100644 --- a/storage/browser/quota/quota_database.cc +++ b/storage/browser/quota/quota_database.cc
@@ -131,7 +131,7 @@ int64_t* quota) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(quota); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -152,8 +152,9 @@ int64_t quota) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_GE(quota, 0); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; + if (quota == 0) return DeleteHostQuota(host, type); if (!InsertOrReplaceHostQuota(host, type, quota)) @@ -167,8 +168,9 @@ const std::string& bucket_name) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // TODO(crbug/1210259): Add DCHECKs for input validation. - if (!LazyOpen(/*create_if_needed=*/true)) - return QuotaError::kDatabaseError; + QuotaError open_error = LazyOpen(LazyOpenMode::kCreateIfNotFound); + if (open_error != QuotaError::kNone) + return open_error; // TODO(crbug/1210252): Update to not execute 2 sql statements on creation. QuotaErrorOr<BucketId> bucket_result = GetBucketId(origin, bucket_name); @@ -216,8 +218,12 @@ const url::Origin& origin, const std::string& bucket_name) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(/*create_if_needed=*/true)) - return QuotaError::kDatabaseError; + QuotaError open_error = LazyOpen(LazyOpenMode::kFailIfNotFound); + if (open_error != QuotaError::kNone) { + if (open_error == QuotaError::kDatabaseNotFound) + return BucketId(); + return open_error; + } static constexpr char kSql[] = "SELECT id FROM buckets WHERE origin = ? AND type = ? AND name = ?"; @@ -239,7 +245,7 @@ StorageType type, base::Time last_accessed) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; sql::Statement statement; @@ -292,7 +298,7 @@ base::Time last_accessed) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!bucket_id.is_null()); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; BucketTableEntry entry; @@ -318,7 +324,7 @@ StorageType type, base::Time last_modified) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; sql::Statement statement; @@ -367,7 +373,7 @@ base::Time last_modified) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!bucket_id.is_null()); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; BucketTableEntry entry; @@ -391,7 +397,7 @@ const std::set<url::Origin>& origins, StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; for (const auto& origin : origins) { @@ -426,7 +432,7 @@ StorageType type, QuotaDatabase::BucketTableEntry* entry) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -458,7 +464,7 @@ QuotaDatabase::BucketTableEntry* entry) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!bucket_id.is_null()); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -491,7 +497,7 @@ bool QuotaDatabase::DeleteHostQuota( const std::string& host, StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -510,7 +516,7 @@ bool QuotaDatabase::DeleteOriginInfo(const url::Origin& origin, StorageType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -530,7 +536,7 @@ bool QuotaDatabase::DeleteBucketInfo(const BucketId bucket_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!bucket_id.is_null()); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = "DELETE FROM buckets WHERE id = ?"; @@ -550,7 +556,7 @@ absl::optional<url::Origin>* origin) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(origin); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -591,7 +597,7 @@ absl::optional<BucketId>* bucket_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(bucket_id); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = @@ -634,7 +640,7 @@ base::Time end) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(origins); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; DCHECK(!begin.is_max()); @@ -665,7 +671,7 @@ base::Time end) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(bucket_ids); - if (!LazyOpen(false)) + if (LazyOpen(LazyOpenMode::kFailIfNotFound) != QuotaError::kNone) return false; DCHECK(!begin.is_max()); @@ -690,7 +696,7 @@ bool QuotaDatabase::IsOriginDatabaseBootstrapped() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; int flag = 0; @@ -699,7 +705,7 @@ bool QuotaDatabase::SetOriginDatabaseBootstrapped(bool bootstrap_flag) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; return meta_table_->SetValue(kIsOriginTableBootstrapped, bootstrap_flag); @@ -728,20 +734,20 @@ this, &QuotaDatabase::Commit); } -bool QuotaDatabase::LazyOpen(bool create_if_needed) { +QuotaError QuotaDatabase::LazyOpen(LazyOpenMode mode) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (db_) - return true; + return QuotaError::kNone; // If we tried and failed once, don't try again in the same session // to avoid creating an incoherent mess on disk. if (is_disabled_) - return false; + return QuotaError::kDatabaseError; bool in_memory_only = db_file_path_.empty(); - if (!create_if_needed && + if (mode == LazyOpenMode::kFailIfNotFound && (in_memory_only || !base::PathExists(db_file_path_))) { - return false; + return QuotaError::kDatabaseNotFound; } db_ = std::make_unique<sql::Database>(sql::DatabaseOptions{ @@ -771,14 +777,14 @@ is_disabled_ = true; db_.reset(); meta_table_.reset(); - return false; + return QuotaError::kDatabaseError; } } // Start a long-running transaction. db_->BeginTransaction(); - return true; + return QuotaError::kNone; } bool QuotaDatabase::EnsureDatabaseVersion() { @@ -880,7 +886,7 @@ return false; base::AutoReset<bool> auto_reset(&is_recreating_, true); - return LazyOpen(true); + return LazyOpen(LazyOpenMode::kCreateIfNotFound) == QuotaError::kNone; } bool QuotaDatabase::InsertOrReplaceHostQuota(const std::string& host, @@ -902,7 +908,7 @@ bool QuotaDatabase::DumpQuotaTable(const QuotaTableCallback& callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] = "SELECT * FROM quota"; @@ -924,7 +930,7 @@ bool QuotaDatabase::DumpBucketTable(const BucketTableCallback& callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!LazyOpen(true)) + if (LazyOpen(LazyOpenMode::kCreateIfNotFound) != QuotaError::kNone) return false; static constexpr char kSql[] =
diff --git a/storage/browser/quota/quota_database.h b/storage/browser/quota/quota_database.h index 70a8aa21..5c1171d 100644 --- a/storage/browser/quota/quota_database.h +++ b/storage/browser/quota/quota_database.h
@@ -67,6 +67,8 @@ base::Time last_modified; }; + enum class LazyOpenMode { kCreateIfNotFound, kFailIfNotFound }; + // If 'path' is empty, an in memory database will be used. explicit QuotaDatabase(const base::FilePath& path); ~QuotaDatabase(); @@ -219,7 +221,7 @@ void Commit(); void ScheduleCommit(); - bool LazyOpen(bool create_if_needed); + QuotaError LazyOpen(LazyOpenMode mode); bool EnsureDatabaseVersion(); bool ResetSchema(); bool UpgradeSchema(int current_version);
diff --git a/storage/browser/quota/quota_database_migrations_unittest.cc b/storage/browser/quota/quota_database_migrations_unittest.cc index f81ec6b..d5970f1 100644 --- a/storage/browser/quota/quota_database_migrations_unittest.cc +++ b/storage/browser/quota/quota_database_migrations_unittest.cc
@@ -59,7 +59,8 @@ void MigrateDatabase() { QuotaDatabase db(DbPath()); - EXPECT_TRUE(db.LazyOpen(true)); + EXPECT_EQ(db.LazyOpen(QuotaDatabase::LazyOpenMode::kCreateIfNotFound), + QuotaError::kNone); EXPECT_TRUE(db.db_.get()); }
diff --git a/storage/browser/quota/quota_database_unittest.cc b/storage/browser/quota/quota_database_unittest.cc index c49573d..2f671e1 100644 --- a/storage/browser/quota/quota_database_unittest.cc +++ b/storage/browser/quota/quota_database_unittest.cc
@@ -14,6 +14,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/test/task_environment.h" +#include "build/build_config.h" #include "sql/database.h" #include "sql/meta_table.h" #include "sql/statement.h" @@ -50,6 +51,7 @@ protected: using QuotaTableEntry = QuotaDatabase::QuotaTableEntry; using BucketTableEntry = QuotaDatabase::BucketTableEntry; + using LazyOpenMode = QuotaDatabase::LazyOpenMode; void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); } @@ -61,8 +63,8 @@ return temp_directory_.GetPath().AppendASCII("quota_manager.db"); } - bool LazyOpen(QuotaDatabase* db, bool create_if_needed) { - return db->LazyOpen(create_if_needed); + bool LazyOpen(QuotaDatabase* db, LazyOpenMode mode) { + return db->LazyOpen(mode) == QuotaError::kNone; } template <typename EntryType> @@ -153,8 +155,8 @@ TEST_P(QuotaDatabaseTest, LazyOpen) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_FALSE(LazyOpen(&db, /*create_if_needed=*/false)); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_FALSE(LazyOpen(&db, LazyOpenMode::kFailIfNotFound)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); if (GetParam()) { // Path should not exist for incognito mode. @@ -166,7 +168,7 @@ TEST_P(QuotaDatabaseTest, HostQuota) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); const char* kHost = "foo.com"; const int kQuota1 = 13579; @@ -200,7 +202,7 @@ TEST_P(QuotaDatabaseTest, CreateBucket) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); url::Origin origin = ToOrigin("http://google/"); std::string bucket_name = "google_bucket"; @@ -216,7 +218,7 @@ TEST_P(QuotaDatabaseTest, GetBucketId) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); // Add a bucket entry into the bucket table. url::Origin origin = ToOrigin("http://google/"); @@ -242,9 +244,41 @@ EXPECT_TRUE(result.value().is_null()); } +TEST_P(QuotaDatabaseTest, GetBucketIdWithNoDb) { + QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); + EXPECT_FALSE(LazyOpen(&db, LazyOpenMode::kFailIfNotFound)); + + url::Origin origin = ToOrigin("http://google/"); + std::string bucket_name = "google_bucket"; + QuotaErrorOr<BucketId> result = db.GetBucketId(origin, bucket_name); + ASSERT_TRUE(result.ok()); + EXPECT_TRUE(result.value().is_null()); +} + +// TODO(crbug.com/1216094): Update test to have its behavior on Fuchsia match +// with other platforms, and enable test on all platforms. +#if !defined(OS_FUCHSIA) +TEST_F(QuotaDatabaseTest, GetBucketIdWithOpenDatabaseError) { + sql::test::ScopedErrorExpecter expecter; + expecter.ExpectError(SQLITE_CANTOPEN); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + QuotaDatabase db(temp_dir.GetPath()); + + url::Origin origin = ToOrigin("http://google/"); + std::string bucket_name = "google_bucket"; + QuotaErrorOr<BucketId> result = db.GetBucketId(origin, bucket_name); + ASSERT_FALSE(result.ok()); + EXPECT_EQ(result.error(), QuotaError::kDatabaseError); + + EXPECT_TRUE(expecter.SawExpectedErrors()); +} +#endif // !defined(OS_FUCHSIA) + TEST_P(QuotaDatabaseTest, OriginLastAccessTimeLRU) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); std::set<url::Origin> exceptions; absl::optional<url::Origin> origin; @@ -314,7 +348,7 @@ TEST_P(QuotaDatabaseTest, BucketLastAccessTimeLRU) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); std::set<url::Origin> exceptions; absl::optional<BucketId> bucket_id; @@ -393,7 +427,7 @@ TEST_P(QuotaDatabaseTest, OriginLastModifiedBetween) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); std::set<url::Origin> origins; EXPECT_TRUE(db.GetOriginsModifiedBetween(kTemp, &origins, base::Time(), @@ -486,7 +520,7 @@ TEST_P(QuotaDatabaseTest, BucketLastModifiedBetween) { QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); std::set<BucketId> bucket_ids; EXPECT_TRUE(db.GetBucketsModifiedBetween(kTemp, &bucket_ids, base::Time(), @@ -607,7 +641,7 @@ {.host = "http://gle/", .type = kPerm, .quota = 3}}; QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); AssignQuotaTable(&db, kTableEntries); using Verifier = EntryVerifier<QuotaTableEntry>; @@ -630,7 +664,7 @@ }; QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); AssignBucketTable(&db, kTableEntries); using Verifier = EntryVerifier<Entry>; @@ -647,7 +681,7 @@ 100, base::Time(), base::Time())}; QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); AssignBucketTable(&db, kTableEntries); { @@ -675,7 +709,7 @@ base::Time())}; QuotaDatabase db(use_in_memory_db() ? base::FilePath() : DbPath()); - EXPECT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + EXPECT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); AssignBucketTable(&db, kTableEntries); { @@ -711,7 +745,7 @@ // Create database, force corruption and close db by leaving scope. { QuotaDatabase db(DbPath()); - ASSERT_TRUE(LazyOpen(&db, /*create_if_needed=*/true)); + ASSERT_TRUE(LazyOpen(&db, LazyOpenMode::kCreateIfNotFound)); ASSERT_TRUE(sql::test::CorruptSizeInHeader(DbPath())); } // Reopen database and verify schema reset on reopen. @@ -719,7 +753,7 @@ sql::test::ScopedErrorExpecter expecter; expecter.ExpectError(SQLITE_CORRUPT); QuotaDatabase db(DbPath()); - ASSERT_TRUE(LazyOpen(&db, /*create_if_needed=*/false)); + ASSERT_TRUE(LazyOpen(&db, LazyOpenMode::kFailIfNotFound)); EXPECT_TRUE(expecter.SawExpectedErrors()); } }
diff --git a/styleguide/java/java.md b/styleguide/java/java.md index 2c6ca80..1cabacb 100644 --- a/styleguide/java/java.md +++ b/styleguide/java/java.md
@@ -94,7 +94,8 @@ the [same scenarios](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++.md#CHECK_DCHECK_and-NOTREACHED) where C++ DCHECK()s make sense. For multi-statement asserts, use -`org.chromium.base.BuildConfig.DCHECK_IS_ON` to guard your code. +`org.chromium.build.BuildConfig.ENABLE_ASSERTS` to guard your code (similar to +`#if DCHECK_IS_ON()` in C++). Example assert: @@ -102,10 +103,14 @@ assert someCallWithoutSideEffects() : "assert description"; ``` -Example use of `DCHECK_IS_ON`: +Example use of `BuildConfig.ENABLE_ASSERTS`: ```java -if (org.chromium.base.BuildConfig.DCHECK_IS_ON) { +import org.chromium.build.BuildConfig; + +... + +if (BuildConfig.ENABLE_ASSERTS) { // Any code here will be stripped in Release by ProGuard. ... }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index b7a52c8..6abc696 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -4689,7 +4689,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -4768,7 +4768,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -4926,7 +4926,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -5005,7 +5005,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 617d594..3ac2ff6 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -30898,7 +30898,7 @@ "--passthrough", "--retry-limit=2" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_chrome", "isolate_profile_data": true, "merge": { "args": [], @@ -30927,7 +30927,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_chrome/" } ], "junit_tests": [ @@ -35612,7 +35612,7 @@ "--passthrough", "--retry-limit=2" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_chrome", "isolate_profile_data": true, "merge": { "args": [], @@ -35641,7 +35641,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_chrome/" }, { "args": [ @@ -35651,7 +35651,7 @@ "--passthrough", "--retry-limit=2" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_monochrome", "isolate_profile_data": true, "merge": { "args": [], @@ -35680,13 +35680,13 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_monochrome/" }, { "args": [ "--extra-browser-args=--enable-crashpad" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_chrome", "isolate_profile_data": true, "merge": { "args": [], @@ -35717,7 +35717,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_chrome/" } ], "junit_tests": [ @@ -44301,7 +44301,7 @@ "--passthrough", "--retry-limit=2" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -44329,7 +44329,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_chrome/" }, { "args": [ @@ -44339,7 +44339,7 @@ "--passthrough", "--retry-limit=2" ], - "isolate_name": "telemetry_perf_unittests", + "isolate_name": "telemetry_perf_unittests_android_monochrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -44367,7 +44367,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/" + "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests_android_monochrome/" } ] }, @@ -53852,7 +53852,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -53932,7 +53932,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54092,7 +54092,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54172,7 +54172,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54397,7 +54397,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54476,7 +54476,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54634,7 +54634,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54713,7 +54713,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -54938,7 +54938,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -55017,7 +55017,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -55175,7 +55175,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M91", - "revision": "version:91.0.4472.95" + "revision": "version:91.0.4472.96" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -55254,7 +55254,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M92", - "revision": "version:92.0.4515.42" + "revision": "version:92.0.4515.43" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.angle.json b/testing/buildbot/chromium.angle.json index 597eae93..e543e52f 100644 --- a/testing/buildbot/chromium.angle.json +++ b/testing/buildbot/chromium.angle.json
@@ -257,7 +257,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -289,7 +289,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] },
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index f1f7c970..90d5bf5 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -43503,7 +43503,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43553,7 +43553,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43603,7 +43603,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43653,7 +43653,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43703,7 +43703,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43753,7 +43753,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43803,7 +43803,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43853,7 +43853,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43903,7 +43903,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -43953,7 +43953,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44003,7 +44003,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44053,7 +44053,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44103,7 +44103,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44153,7 +44153,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44203,7 +44203,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44253,7 +44253,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44303,7 +44303,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44353,7 +44353,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -44424,7 +44424,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44469,7 +44469,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44514,7 +44514,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44559,7 +44559,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44604,7 +44604,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44649,7 +44649,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44694,7 +44694,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44739,7 +44739,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44784,7 +44784,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44829,7 +44829,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44874,7 +44874,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44919,7 +44919,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -44964,7 +44964,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -45009,7 +45009,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -45054,7 +45054,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -45099,7 +45099,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -45144,7 +45144,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600, @@ -45189,7 +45189,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "expiration": 21600,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 685ffbd..10836a4 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -20959,6 +20959,428 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/" + }, + { + "args": [ + "--num-retries=3", + "--device=aemu" + ], + "isolate_name": "blink_web_tests", + "merge": { + "args": [ + "--verbose" + ], + "script": "//third_party/blink/tools/merge_web_test_results.py" + }, + "name": "blink_web_tests", + "resultdb": { + "enable": true + }, + "results_handler": "layout tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 12 + }, + "test_id_prefix": "ninja://:blink_web_tests/" + }, + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_validating_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "depth_capture", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "depth_capture_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "gpu_process", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "gpu_process_launch_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "hardware_accelerated_feature_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "info_collection", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--expected-vendor-id", + "0", + "--expected-device-id", + "0", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "info_collection_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "maps", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu", + "--git-revision=${got_revision}" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "maps_tests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "mediapipe", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "mediapipe_validating_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu", + "--git-revision=${got_revision}" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_tests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "trace_test", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=web-engine-shell", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--device=aemu" + ], + "isolate_name": "fuchsia_telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_tests", + "resultdb": { + "enable": true + }, + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "arm64", + "inside_docker": "1", + "os": "Ubuntu-20.04" + } + ], + "idempotent": false, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 18 + }, + "test_id_prefix": "ninja://content/test:fuchsia_telemetry_gpu_integration_test/" } ] }, @@ -22887,7 +23309,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22937,7 +23359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22987,7 +23409,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23037,7 +23459,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23087,7 +23509,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23137,7 +23559,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23187,7 +23609,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23237,7 +23659,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23287,7 +23709,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23337,7 +23759,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23387,7 +23809,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23437,7 +23859,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23487,7 +23909,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23537,7 +23959,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23587,7 +24009,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23637,7 +24059,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23687,7 +24109,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23737,7 +24159,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23787,7 +24209,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23837,7 +24259,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23887,7 +24309,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23937,7 +24359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -23987,7 +24409,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24037,7 +24459,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24087,7 +24509,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24137,7 +24559,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24187,7 +24609,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24237,7 +24659,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24287,7 +24709,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24337,7 +24759,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24387,7 +24809,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24437,7 +24859,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24487,7 +24909,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24537,7 +24959,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24587,7 +25009,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24637,7 +25059,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24687,7 +25109,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24737,7 +25159,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24787,7 +25209,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24837,7 +25259,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24887,7 +25309,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24937,7 +25359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -24987,7 +25409,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25037,7 +25459,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25087,7 +25509,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25137,7 +25559,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25194,7 +25616,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25247,7 +25669,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25300,7 +25722,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25353,7 +25775,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25406,7 +25828,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25459,7 +25881,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25512,7 +25934,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25565,7 +25987,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25618,7 +26040,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25671,7 +26093,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25724,7 +26146,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25777,7 +26199,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25830,7 +26252,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25883,7 +26305,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25936,7 +26358,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -25989,7 +26411,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26042,7 +26464,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26095,7 +26517,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26148,7 +26570,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26201,7 +26623,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26254,7 +26676,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26307,7 +26729,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26360,7 +26782,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26413,7 +26835,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26466,7 +26888,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26519,7 +26941,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26572,7 +26994,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26625,7 +27047,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26678,7 +27100,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26731,7 +27153,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26784,7 +27206,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26837,7 +27259,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26890,7 +27312,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26943,7 +27365,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -26997,7 +27419,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27051,7 +27473,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27105,7 +27527,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27159,7 +27581,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27213,7 +27635,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27267,7 +27689,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27321,7 +27743,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27376,7 +27798,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27431,7 +27853,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27486,7 +27908,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27541,7 +27963,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27596,7 +28018,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27651,7 +28073,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27706,7 +28128,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27761,7 +28183,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27816,7 +28238,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27871,7 +28293,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27926,7 +28348,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -27981,7 +28403,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28035,7 +28457,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28089,7 +28511,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28143,7 +28565,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28197,7 +28619,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28251,7 +28673,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28305,7 +28727,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28359,7 +28781,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28413,7 +28835,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28467,7 +28889,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28521,7 +28943,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28575,7 +28997,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28629,7 +29051,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28684,7 +29106,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28739,7 +29161,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28794,7 +29216,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28849,7 +29271,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28904,7 +29326,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -28958,7 +29380,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29011,7 +29433,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29064,7 +29486,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29117,7 +29539,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29170,7 +29592,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29223,7 +29645,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29276,7 +29698,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29329,7 +29751,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29383,7 +29805,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29437,7 +29859,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29491,7 +29913,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29545,7 +29967,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29599,7 +30021,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29653,7 +30075,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29706,7 +30128,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29759,7 +30181,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29812,7 +30234,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29865,7 +30287,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29918,7 +30340,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -29971,7 +30393,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30025,7 +30447,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30079,7 +30501,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30133,7 +30555,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30187,7 +30609,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30241,7 +30663,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30295,7 +30717,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30348,7 +30770,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30401,7 +30823,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30454,7 +30876,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30507,7 +30929,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30560,7 +30982,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30613,7 +31035,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30666,7 +31088,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30719,7 +31141,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30772,7 +31194,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30825,7 +31247,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30879,7 +31301,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30933,7 +31355,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -30987,7 +31409,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31041,7 +31463,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31095,7 +31517,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31149,7 +31571,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31202,7 +31624,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31255,7 +31677,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31308,7 +31730,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31361,7 +31783,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31414,7 +31836,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31467,7 +31889,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31520,7 +31942,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31573,7 +31995,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31626,7 +32048,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31679,7 +32101,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31732,7 +32154,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31785,7 +32207,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31838,7 +32260,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31891,7 +32313,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31944,7 +32366,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -31997,7 +32419,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32050,7 +32472,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32103,7 +32525,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32156,7 +32578,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32209,7 +32631,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32262,7 +32684,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32315,7 +32737,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32368,7 +32790,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32421,7 +32843,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32474,7 +32896,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32527,7 +32949,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32580,7 +33002,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32633,7 +33055,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32686,7 +33108,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32739,7 +33161,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32792,7 +33214,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32845,7 +33267,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32898,7 +33320,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -32951,7 +33373,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33004,7 +33426,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33057,7 +33479,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33110,7 +33532,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33163,7 +33585,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33216,7 +33638,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33269,7 +33691,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33322,7 +33744,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33375,7 +33797,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33428,7 +33850,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33481,7 +33903,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33534,7 +33956,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33587,7 +34009,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33640,7 +34062,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33693,7 +34115,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33747,7 +34169,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33797,7 +34219,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33851,7 +34273,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33901,7 +34323,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -33951,7 +34373,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34001,7 +34423,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34051,7 +34473,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34101,7 +34523,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34151,7 +34573,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34201,7 +34623,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34252,7 +34674,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34303,7 +34725,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34355,7 +34777,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34407,7 +34829,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34458,7 +34880,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34509,7 +34931,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34560,7 +34982,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34611,7 +35033,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34661,7 +35083,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34711,7 +35133,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34761,7 +35183,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34812,7 +35234,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34862,7 +35284,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34912,7 +35334,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -34963,7 +35385,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35013,7 +35435,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35063,7 +35485,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35113,7 +35535,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35163,7 +35585,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35213,7 +35635,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35263,7 +35685,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35313,7 +35735,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35363,7 +35785,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35413,7 +35835,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35469,7 +35891,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35521,7 +35943,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35573,7 +35995,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35625,7 +36047,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35677,7 +36099,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35729,7 +36151,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35781,7 +36203,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35833,7 +36255,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35885,7 +36307,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35937,7 +36359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -35989,7 +36411,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36041,7 +36463,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36093,7 +36515,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36145,7 +36567,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36197,7 +36619,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36249,7 +36671,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36302,7 +36724,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36355,7 +36777,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36408,7 +36830,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36462,7 +36884,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36516,7 +36938,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36570,7 +36992,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36624,7 +37046,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36677,7 +37099,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36730,7 +37152,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36783,7 +37205,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36836,7 +37258,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36890,7 +37312,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36943,7 +37365,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -36995,7 +37417,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37048,7 +37470,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37101,7 +37523,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37153,7 +37575,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37205,7 +37627,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37257,7 +37679,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37309,7 +37731,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37361,7 +37783,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37413,7 +37835,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37466,7 +37888,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37519,7 +37941,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37571,7 +37993,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37623,7 +38045,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37675,7 +38097,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37727,7 +38149,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37780,7 +38202,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37833,7 +38255,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37885,7 +38307,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37937,7 +38359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -37989,7 +38411,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38041,7 +38463,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38093,7 +38515,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38145,7 +38567,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38197,7 +38619,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38249,7 +38671,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38301,7 +38723,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38353,7 +38775,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38405,7 +38827,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38457,7 +38879,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38509,7 +38931,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38561,7 +38983,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38613,7 +39035,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38665,7 +39087,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38717,7 +39139,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -38769,7 +39191,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 7686000..f6db2b6 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -134,7 +134,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -166,7 +166,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -2139,7 +2139,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2171,7 +2171,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2182,7 +2182,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2214,7 +2214,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2225,7 +2225,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2257,7 +2257,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2268,7 +2268,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2300,7 +2300,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2315,7 +2315,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2347,7 +2347,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2362,7 +2362,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2399,7 +2399,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2414,7 +2414,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2451,7 +2451,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2463,7 +2463,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2495,7 +2495,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2506,7 +2506,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2538,7 +2538,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2550,7 +2550,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2583,7 +2583,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -2777,7 +2777,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2809,7 +2809,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2820,7 +2820,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2852,7 +2852,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2863,7 +2863,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2895,7 +2895,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2906,7 +2906,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2938,7 +2938,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -2953,7 +2953,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -2985,7 +2985,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3000,7 +3000,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3037,7 +3037,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3052,7 +3052,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3089,7 +3089,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3101,7 +3101,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3133,7 +3133,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3144,7 +3144,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3176,7 +3176,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3188,7 +3188,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3221,7 +3221,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -3326,7 +3326,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_webview", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3362,7 +3362,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_webview/" }, { "args": [ @@ -3417,7 +3417,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3448,7 +3448,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3459,7 +3459,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3490,7 +3490,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3501,7 +3501,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3532,7 +3532,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3543,7 +3543,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3574,7 +3574,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3589,7 +3589,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3620,7 +3620,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3635,7 +3635,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3671,7 +3671,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3682,7 +3682,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3713,7 +3713,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3724,7 +3724,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3755,7 +3755,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3770,7 +3770,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3806,7 +3806,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3814,7 +3814,7 @@ "--benchmarks=rendering.mobile", "--browser=android-chromium" ], - "isolate_name": "rendering_representative_perf_tests", + "isolate_name": "rendering_representative_perf_tests_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3843,7 +3843,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/" + "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests_android_chrome/" }, { "args": [ @@ -3855,7 +3855,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3886,7 +3886,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3897,7 +3897,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3928,7 +3928,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3939,7 +3939,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -3970,7 +3970,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -3982,7 +3982,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4014,7 +4014,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4026,7 +4026,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4058,7 +4058,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -4252,7 +4252,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4284,7 +4284,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4295,7 +4295,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4327,7 +4327,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4338,7 +4338,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4370,7 +4370,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4381,7 +4381,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4413,7 +4413,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4428,7 +4428,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4460,7 +4460,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4475,7 +4475,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4512,7 +4512,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4527,7 +4527,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4564,7 +4564,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4576,7 +4576,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4608,7 +4608,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4619,7 +4619,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4651,7 +4651,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4663,7 +4663,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4696,7 +4696,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -4935,7 +4935,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -4967,7 +4967,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -4978,7 +4978,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5010,7 +5010,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5021,7 +5021,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5053,7 +5053,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5064,7 +5064,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5096,7 +5096,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5111,7 +5111,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5143,7 +5143,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5158,7 +5158,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5195,7 +5195,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5210,7 +5210,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5247,7 +5247,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5259,7 +5259,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5291,7 +5291,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5302,7 +5302,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5334,7 +5334,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5346,7 +5346,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5379,7 +5379,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -5398,7 +5398,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5435,7 +5435,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5447,7 +5447,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5479,7 +5479,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5492,7 +5492,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5525,7 +5525,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5538,7 +5538,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5571,7 +5571,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -5590,7 +5590,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_webview", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5627,7 +5627,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_webview/" }, { "args": [ @@ -5638,7 +5638,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5670,7 +5670,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5681,7 +5681,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5713,7 +5713,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5724,7 +5724,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5756,7 +5756,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5767,7 +5767,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5799,7 +5799,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5810,7 +5810,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5842,7 +5842,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5857,7 +5857,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5889,7 +5889,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5904,7 +5904,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5941,7 +5941,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -5956,7 +5956,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -5993,7 +5993,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6004,7 +6004,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6036,7 +6036,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6047,7 +6047,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6079,7 +6079,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6094,7 +6094,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6131,7 +6131,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6146,7 +6146,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6183,7 +6183,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6195,7 +6195,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --force-online-connection-state-for-indicator --disable-wcg-for-test", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6227,7 +6227,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6239,7 +6239,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator --disable-wcg-for-test", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6271,7 +6271,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6282,7 +6282,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6314,7 +6314,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6325,7 +6325,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6357,7 +6357,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6370,7 +6370,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6403,7 +6403,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6416,7 +6416,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6449,7 +6449,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6461,7 +6461,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6494,7 +6494,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -6506,7 +6506,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6539,7 +6539,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -6558,7 +6558,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6594,7 +6594,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -6667,7 +6667,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -6704,7 +6704,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] }, @@ -26032,7 +26032,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_webview", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26069,7 +26069,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_webview/" }, { "args": [ @@ -26080,7 +26080,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26112,7 +26112,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26123,7 +26123,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26155,7 +26155,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26166,7 +26166,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26198,7 +26198,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26209,7 +26209,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26241,7 +26241,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26252,7 +26252,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26284,7 +26284,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26299,7 +26299,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26331,7 +26331,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26346,7 +26346,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26383,7 +26383,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26398,7 +26398,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26435,7 +26435,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26446,7 +26446,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26478,7 +26478,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26489,7 +26489,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26521,7 +26521,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26536,7 +26536,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26573,7 +26573,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26588,7 +26588,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26625,7 +26625,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26637,7 +26637,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --force-online-connection-state-for-indicator --disable-wcg-for-test", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26669,7 +26669,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26681,7 +26681,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator --disable-wcg-for-test", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26713,7 +26713,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26724,7 +26724,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26756,7 +26756,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26767,7 +26767,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26799,7 +26799,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26812,7 +26812,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26845,7 +26845,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26858,7 +26858,7 @@ "--webgl-conformance-version=2.0.1", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26891,7 +26891,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 20 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26903,7 +26903,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26936,7 +26936,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -26948,7 +26948,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -26981,7 +26981,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] },
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index 3782138..eb4d85e 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -12,7 +12,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -43,7 +43,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -54,7 +54,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -85,7 +85,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -96,7 +96,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -127,7 +127,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -138,7 +138,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -169,7 +169,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -184,7 +184,7 @@ "--expected-device-id", "0" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -215,7 +215,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -230,7 +230,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -266,7 +266,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -281,7 +281,7 @@ "${buildername}", "--git-revision=${got_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -317,7 +317,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -326,7 +326,7 @@ "--browser=android-chromium" ], "experiment_percentage": 10, - "isolate_name": "rendering_representative_perf_tests", + "isolate_name": "rendering_representative_perf_tests_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -352,7 +352,7 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/" + "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests_android_chrome/" }, { "args": [ @@ -364,7 +364,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -395,7 +395,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -406,7 +406,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -437,7 +437,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -449,7 +449,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -481,7 +481,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 12 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] },
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index cfe6974..6683003 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -7985,6 +7985,7 @@ "test_id_prefix": "ninja://headless:headless_unittests/" }, { + "ci_only": true, "isolate_profile_data": true, "merge": { "args": [], @@ -8740,6 +8741,7 @@ "args": [ "--num-retries=3" ], + "ci_only": true, "isolate_name": "blink_web_tests", "isolate_profile_data": true, "merge": { @@ -12726,7 +12728,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -12777,7 +12779,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -12828,7 +12830,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -12879,7 +12881,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -12930,7 +12932,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -12981,7 +12983,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13032,7 +13034,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13083,7 +13085,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13134,7 +13136,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13185,7 +13187,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13236,7 +13238,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13287,7 +13289,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13338,7 +13340,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13389,7 +13391,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13440,7 +13442,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13491,7 +13493,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13542,7 +13544,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13593,7 +13595,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13644,7 +13646,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13695,7 +13697,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13746,7 +13748,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13797,7 +13799,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13848,7 +13850,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13899,7 +13901,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -13950,7 +13952,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14001,7 +14003,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14052,7 +14054,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14103,7 +14105,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14154,7 +14156,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14205,7 +14207,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14256,7 +14258,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14307,7 +14309,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14358,7 +14360,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14409,7 +14411,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14461,7 +14463,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14514,7 +14516,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14567,7 +14569,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14619,7 +14621,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14671,7 +14673,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14724,7 +14726,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14776,7 +14778,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14827,7 +14829,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14878,7 +14880,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14929,7 +14931,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -14980,7 +14982,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15031,7 +15033,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15082,7 +15084,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15133,7 +15135,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15184,7 +15186,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15235,7 +15237,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15286,7 +15288,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15337,7 +15339,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15388,7 +15390,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15439,7 +15441,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15490,7 +15492,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15541,7 +15543,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15592,7 +15594,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15643,7 +15645,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15694,7 +15696,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15745,7 +15747,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15796,7 +15798,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15847,7 +15849,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15898,7 +15900,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -15949,7 +15951,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16001,7 +16003,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16053,7 +16055,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16104,7 +16106,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16155,7 +16157,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16206,7 +16208,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16257,7 +16259,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16308,7 +16310,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16359,7 +16361,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16410,7 +16412,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16461,7 +16463,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16512,7 +16514,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16563,7 +16565,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16614,7 +16616,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16665,7 +16667,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16716,7 +16718,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16767,7 +16769,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16818,7 +16820,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16869,7 +16871,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16920,7 +16922,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -16971,7 +16973,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17022,7 +17024,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17073,7 +17075,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17124,7 +17126,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17175,7 +17177,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17226,7 +17228,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17277,7 +17279,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17328,7 +17330,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17379,7 +17381,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17430,7 +17432,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17481,7 +17483,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17532,7 +17534,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17583,7 +17585,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17634,7 +17636,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17685,7 +17687,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17736,7 +17738,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17787,7 +17789,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17838,7 +17840,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17889,7 +17891,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17940,7 +17942,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -17991,7 +17993,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18042,7 +18044,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18093,7 +18095,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18144,7 +18146,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18195,7 +18197,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18246,7 +18248,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18297,7 +18299,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18348,7 +18350,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18399,7 +18401,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18450,7 +18452,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18501,7 +18503,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18560,7 +18562,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18612,7 +18614,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18664,7 +18666,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18716,7 +18718,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18768,7 +18770,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18820,7 +18822,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18872,7 +18874,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18925,7 +18927,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -18978,7 +18980,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19031,7 +19033,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19084,7 +19086,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19137,7 +19139,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19190,7 +19192,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19243,7 +19245,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19296,7 +19298,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19349,7 +19351,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19402,7 +19404,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19454,7 +19456,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19506,7 +19508,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19558,7 +19560,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19610,7 +19612,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19662,7 +19664,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19714,7 +19716,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19766,7 +19768,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19818,7 +19820,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19870,7 +19872,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19922,7 +19924,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -19975,7 +19977,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20028,7 +20030,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20081,7 +20083,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20134,7 +20136,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20186,7 +20188,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20238,7 +20240,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20290,7 +20292,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20342,7 +20344,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20394,7 +20396,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20446,7 +20448,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20498,7 +20500,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20550,7 +20552,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20602,7 +20604,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20654,7 +20656,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20706,7 +20708,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20758,7 +20760,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20810,7 +20812,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20862,7 +20864,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20914,7 +20916,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -20971,7 +20973,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21021,7 +21023,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21071,7 +21073,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21121,7 +21123,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21171,7 +21173,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21222,7 +21224,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21273,7 +21275,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21324,7 +21326,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21376,7 +21378,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21428,7 +21430,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21480,7 +21482,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21532,7 +21534,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21583,7 +21585,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21634,7 +21636,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21685,7 +21687,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21736,7 +21738,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21788,7 +21790,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21840,7 +21842,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21891,7 +21893,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21941,7 +21943,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -21991,7 +21993,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22041,7 +22043,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22092,7 +22094,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22143,7 +22145,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22193,7 +22195,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22244,7 +22246,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22295,7 +22297,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22345,7 +22347,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22395,7 +22397,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22445,7 +22447,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [ @@ -22495,7 +22497,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15|Mac-10.16|Mac-11" + "os": "Mac-11|Mac-10.16" } ], "named_caches": [
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json index c7a85ad..6985b939 100644 --- a/testing/buildbot/client.v8.fyi.json +++ b/testing/buildbot/client.v8.fyi.json
@@ -12,7 +12,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -42,7 +42,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -53,7 +53,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -83,7 +83,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -94,7 +94,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -124,7 +124,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -135,7 +135,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -165,7 +165,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -180,7 +180,7 @@ "${buildername}", "--git-revision=${got_cr_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -215,7 +215,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -230,7 +230,7 @@ "${buildername}", "--git-revision=${got_cr_revision}" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -265,7 +265,7 @@ "idempotent": false, "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -277,7 +277,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force-online-connection-state-for-indicator", "--dont-restore-color-profile-after-test" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -307,7 +307,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -318,7 +318,7 @@ "-v", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -348,7 +348,7 @@ "idempotent": false, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -360,7 +360,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -391,7 +391,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" }, { "args": [ @@ -403,7 +403,7 @@ "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating --force_high_performance_gpu", "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json" ], - "isolate_name": "telemetry_gpu_integration_test", + "isolate_name": "telemetry_gpu_integration_test_android_chrome", "merge": { "args": [], "script": "//testing/merge_scripts/standard_isolated_script_merge.py" @@ -434,7 +434,7 @@ "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", "shards": 6 }, - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" } ] },
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py index 9abc2185..7d3d20d 100755 --- a/testing/buildbot/generate_buildbot_json.py +++ b/testing/buildbot/generate_buildbot_json.py
@@ -26,6 +26,13 @@ THIS_DIR = os.path.dirname(os.path.abspath(__file__)) +BROWSER_CONFIG_TO_TARGET_SUFFIX_MAP = { + 'android-chromium': '_android_chrome', + 'android-chromium-monochrome': '_android_monochrome', + 'android-weblayer': '_android_weblayer', + 'android-webview': '_android_webview', +} + class BBGenErr(Exception): def __init__(self, message): @@ -921,12 +928,11 @@ if not result: return None result['isolate_name'] = test_config.get( - 'isolate_name', 'telemetry_gpu_integration_test') + 'isolate_name', + self.get_default_isolate_name(tester_config, is_android_webview)) # Populate test_id_prefix. - gn_entry = ( - self.gn_isolate_map.get(result['isolate_name']) or - self.gn_isolate_map.get('telemetry_gpu_integration_test')) + gn_entry = self.gn_isolate_map[result['isolate_name']] result['test_id_prefix'] = 'ninja:%s/' % gn_entry['label'] args = result.get('args', []) @@ -969,6 +975,16 @@ tester_config, result['swarming'], args)) return result + def get_default_isolate_name(self, tester_config, is_android_webview): + if self.is_android(tester_config): + if is_android_webview: + return 'telemetry_gpu_integration_test_android_webview' + return ( + 'telemetry_gpu_integration_test' + + BROWSER_CONFIG_TO_TARGET_SUFFIX_MAP[tester_config['browser_config']]) + else: + return 'telemetry_gpu_integration_test' + def get_test_generator_map(self): return { 'android_webview_gpu_telemetry_tests':
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py index fc8c000..15bcdc1 100755 --- a/testing/buildbot/generate_buildbot_json_unittest.py +++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -355,6 +355,58 @@ ] """ +FOO_GPU_TELEMETRY_TEST_WATERFALL_ANDROID = """\ +[ + { + 'project': 'chromium', + 'bucket': 'ci', + 'name': 'chromium.test', + 'machines': { + 'Fake Tester': { + 'os_type': 'android', + 'browser_config': 'android-chromium', + 'swarming': { + 'dimension_sets': [ + { + 'device_type': 'bullhead', + }, + ], + }, + 'test_suites': { + 'gpu_telemetry_tests': 'composition_tests', + }, + }, + }, + }, +] +""" + +FOO_GPU_TELEMETRY_TEST_WATERFALL_ANDROID_WEBVIEW = """\ +[ + { + 'project': 'chromium', + 'bucket': 'ci', + 'name': 'chromium.test', + 'machines': { + 'Fake Tester': { + 'os_type': 'android', + 'browser_config': 'not-a-real-browser', + 'swarming': { + 'dimension_sets': [ + { + 'device_type': 'bullhead', + }, + ], + }, + 'test_suites': { + 'android_webview_gpu_telemetry_tests': 'composition_tests', + }, + }, + }, + }, +] +""" + NVIDIA_GPU_TELEMETRY_TEST_WATERFALL = """\ [ { @@ -1554,6 +1606,96 @@ } """ +GPU_TELEMETRY_TEST_OUTPUT_ANDROID = """\ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "Fake Tester": { + "isolated_scripts": [ + { + "args": [ + "foo", + "--show-stdout", + "--browser=android-chromium", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test_android_chrome", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "foo_tests", + "should_retry_with_patch": false, + "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_type": "bullhead" + } + ], + "idempotent": false + }, + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_chrome/" + } + ] + } +} +""" + +GPU_TELEMETRY_TEST_OUTPUT_ANDROID_WEBVIEW = """\ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "Fake Tester": { + "isolated_scripts": [ + { + "args": [ + "foo", + "--show-stdout", + "--browser=android-webview-instrumentation", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test_android_webview", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "foo_tests", + "should_retry_with_patch": false, + "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_type": "bullhead" + } + ], + "idempotent": false + }, + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test_android_webview/" + } + ] + } +} +""" + NVIDIA_GPU_TELEMETRY_TEST_OUTPUT = """\ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, @@ -2146,6 +2288,25 @@ } } """ + +GPU_TELEMETRY_GN_ISOLATE_MAP_ANDROID = """\ +{ + 'telemetry_gpu_integration_test_android_chrome': { + 'label': '//chrome/test:telemetry_gpu_integration_test_android_chrome', + 'type': 'script', + } +} +""" + +GPU_TELEMETRY_GN_ISOLATE_MAP_ANDROID_WEBVIEW = """\ +{ + 'telemetry_gpu_integration_test_android_webview': { + 'label': '//chrome/test:telemetry_gpu_integration_test_android_webview', + 'type': 'script', + } +} +""" + GN_ISOLATE_MAP_KEY_LABEL_MISMATCH="""\ { 'foo_test': { @@ -2476,6 +2637,34 @@ fbb.check_output_file_consistency(verbose=True) self.assertFalse(fbb.printed_lines) + def test_gpu_telemetry_tests_android(self): + fbb = FakeBBGen(self.args, + FOO_GPU_TELEMETRY_TEST_WATERFALL_ANDROID, + COMPOSITION_SUITE_WITH_NAME_NOT_ENDING_IN_TEST, + LUCI_MILO_CFG, + exceptions=NO_BAR_TEST_EXCEPTIONS, + gn_isolate_map=GPU_TELEMETRY_GN_ISOLATE_MAP_ANDROID) + self.create_testing_buildbot_json_file('chromium.test.json', + GPU_TELEMETRY_TEST_OUTPUT_ANDROID) + self.create_testing_buildbot_json_file('chromium.ci.json', + GPU_TELEMETRY_TEST_OUTPUT_ANDROID) + fbb.check_output_file_consistency(verbose=True) + self.assertFalse(fbb.printed_lines) + + def test_gpu_telemetry_tests_android_webview(self): + fbb = FakeBBGen(self.args, + FOO_GPU_TELEMETRY_TEST_WATERFALL_ANDROID_WEBVIEW, + COMPOSITION_SUITE_WITH_NAME_NOT_ENDING_IN_TEST, + LUCI_MILO_CFG, + exceptions=NO_BAR_TEST_EXCEPTIONS, + gn_isolate_map=GPU_TELEMETRY_GN_ISOLATE_MAP_ANDROID_WEBVIEW) + self.create_testing_buildbot_json_file( + 'chromium.test.json', GPU_TELEMETRY_TEST_OUTPUT_ANDROID_WEBVIEW) + self.create_testing_buildbot_json_file( + 'chromium.ci.json', GPU_TELEMETRY_TEST_OUTPUT_ANDROID_WEBVIEW) + fbb.check_output_file_consistency(verbose=True) + self.assertFalse(fbb.printed_lines) + def test_nvidia_gpu_telemetry_tests(self): fbb = FakeBBGen(self.args, NVIDIA_GPU_TELEMETRY_TEST_WATERFALL,
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index d7706c7..bd85c3cc 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1541,6 +1541,16 @@ "script": "//testing/scripts/run_rendering_benchmark_with_gated_performance.py", "type": "script", }, + "rendering_representative_perf_tests_android_chrome": { + "args": [ + "--output-format=csv", + "--browser=release", + "--upload-results", + ], + "label": "//chrome/test:rendering_representative_perf_tests_android_chrome", + "script": "//testing/scripts/run_rendering_benchmark_with_gated_performance.py", + "type": "script", + }, "resource_sizes_chrome_modern_public_minimal_apks": { "label": "//chrome/android:resource_sizes_chrome_modern_public_minimal_apks", "type": "generated_script", @@ -1678,6 +1688,22 @@ "script": "//testing/scripts/run_gpu_integration_test_as_googletest.py", "type": "script", }, + "telemetry_gpu_integration_test_android_chrome": { + "args": [ + "../../content/test/gpu/run_gpu_integration_test.py", + ], + "label": "//chrome/test:telemetry_gpu_integration_test_android_chrome", + "script": "//testing/scripts/run_gpu_integration_test_as_googletest.py", + "type": "script", + }, + "telemetry_gpu_integration_test_android_webview": { + "args": [ + "../../content/test/gpu/run_gpu_integration_test.py", + ], + "label": "//chrome/test:telemetry_gpu_integration_test_android_webview", + "script": "//testing/scripts/run_gpu_integration_test_as_googletest.py", + "type": "script", + }, "telemetry_gpu_integration_test_scripts_only": { "label": "//chrome/test:telemetry_gpu_integration_test_scripts_only", "type": "additional_compile_target", @@ -1710,6 +1736,24 @@ "script": "//testing/scripts/run_telemetry_as_googletest.py", "type": "script", }, + "telemetry_perf_unittests_android_chrome": { + "args": [ + "../../tools/perf/run_tests", + "-v", + ], + "label": "//chrome/test:telemetry_perf_unittests_android_chrome", + "script": "//testing/scripts/run_telemetry_as_googletest.py", + "type": "script", + }, + "telemetry_perf_unittests_android_monochrome": { + "args": [ + "../../tools/perf/run_tests", + "-v", + ], + "label": "//chrome/test:telemetry_perf_unittests_android_monochrome", + "script": "//testing/scripts/run_telemetry_as_googletest.py", + "type": "script", + }, "telemetry_unittests": { "args": [ "--xvfb",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 8b4854e..402e249 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -675,14 +675,6 @@ }, }, }, - 'mac_10.15_or_mac_11': { - 'swarming': { - 'dimensions': { - 'cpu': 'x86-64', - 'os': 'Mac-10.15|Mac-10.16|Mac-11', - }, - }, - }, 'mac_11_beta_x64': { 'swarming': { 'dimensions': {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 7da90af..bd4e971 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -273,6 +273,7 @@ }, }, 'Mac10.15 Tests': { + 'ci_only': True, 'swarming': { 'dimension_sets': [ { @@ -1796,6 +1797,9 @@ 'shards': 32, # Adjusted for testing, see https://crbug.com/1179567 }, }, + 'Mac10.15 Tests': { + 'ci_only': True, + }, 'Mac11 Tests': { # TODO(crbug.com/1206401): Restore to defaults when there is enough # capacity.
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 5864a6be0..1850858 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4752,7 +4752,7 @@ 'rendering_mobile_representative_perf_tests_isolated_scripts': { 'rendering_representative_perf_tests': { - 'isolate_name': 'rendering_representative_perf_tests', + 'isolate_name': 'rendering_representative_perf_tests_android_chrome', 'args': [ "../../tools/perf/run_benchmark", "--benchmarks=rendering.mobile", @@ -4764,7 +4764,7 @@ 'rendering_mobile_representative_perf_tests_isolated_scripts_experimental': { 'rendering_representative_perf_tests': { - 'isolate_name': 'rendering_representative_perf_tests', + 'isolate_name': 'rendering_representative_perf_tests_android_chrome', 'args': [ "../../tools/perf/run_benchmark", "--benchmarks=rendering.mobile", @@ -5044,7 +5044,7 @@ '--passthrough', '--retry-limit=2', ], - 'isolate_name': 'telemetry_perf_unittests', + 'isolate_name': 'telemetry_perf_unittests_android_chrome', 'resultdb': { 'enable': True, }, @@ -5057,7 +5057,7 @@ '--passthrough', '--retry-limit=2', ], - 'isolate_name': 'telemetry_perf_unittests', + 'isolate_name': 'telemetry_perf_unittests_android_monochrome', 'resultdb': { 'enable': True, }, @@ -5096,6 +5096,23 @@ }, }, + 'telemetry_perf_unittests_isolated_scripts_android': { + 'telemetry_perf_unittests': { + 'isolate_name': 'telemetry_perf_unittests_android_chrome', + 'args': [ + # TODO(crbug.com/1077284): Remove this once Crashpad is the default. + '--extra-browser-args=--enable-crashpad', + ], + 'swarming': { + 'idempotent': False, # https://crbug.com/549140 + 'shards': 12, + }, + 'resultdb': { + 'enable': True, + }, + }, + }, + 'test_buildbucket_api_gpu_use_cases': { 'test_buildbucket_api_gpu_use_cases': {}, }, @@ -5974,7 +5991,7 @@ 'web_engine_gtests', ], - 'fuchsia_x64_isolated_scripts': [ + 'fuchsia_isolated_scripts': [ 'chromium_webkit_isolated_scripts', 'gpu_angle_fuchsia_unittests_isolated_scripts' ], @@ -6750,14 +6767,14 @@ 'components_perftests_isolated_scripts', 'monochrome_public_apk_checker_isolated_script', 'telemetry_android_minidump_unittests_isolated_scripts', - 'telemetry_perf_unittests_isolated_scripts', + 'telemetry_perf_unittests_isolated_scripts_android', ], 'marshmallow_pie_isolated_scripts': [ 'android_isolated_scripts', 'components_perftests_isolated_scripts', 'telemetry_android_minidump_unittests_isolated_scripts', - 'telemetry_perf_unittests_isolated_scripts', + 'telemetry_perf_unittests_isolated_scripts_android', ], 'mojo_android_gtests': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 9de8d2e..6138c29 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -400,7 +400,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M92', - 'revision': 'version:92.0.4515.42', + 'revision': 'version:92.0.4515.43', } ], }, @@ -424,7 +424,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M91', - 'revision': 'version:91.0.4472.95', + 'revision': 'version:91.0.4472.96', } ], }, @@ -472,7 +472,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M92', - 'revision': 'version:92.0.4515.42', + 'revision': 'version:92.0.4515.43', } ], }, @@ -496,7 +496,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M91', - 'revision': 'version:91.0.4472.95', + 'revision': 'version:91.0.4472.96', } ], }, @@ -544,7 +544,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M92', - 'revision': 'version:92.0.4515.42', + 'revision': 'version:92.0.4515.43', } ], }, @@ -568,7 +568,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M91', - 'revision': 'version:91.0.4472.95', + 'revision': 'version:91.0.4472.96', } ], },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index adf28df..a58fe91 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1746,7 +1746,7 @@ }, 'test_suites': { 'gtest_tests': 'fuchsia_gtests', - 'isolated_scripts': 'fuchsia_x64_isolated_scripts', + 'isolated_scripts': 'fuchsia_isolated_scripts', 'gpu_telemetry_tests': 'fuchsia_gpu_telemetry_tests', }, }, @@ -2041,7 +2041,7 @@ ], 'mixins': [ 'enable_resultdb', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2075,7 +2075,7 @@ 'enable_resultdb', 'ios_restart_device', 'limited_capacity_bot', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2809,9 +2809,12 @@ 'additional_compile_targets': [ 'all', ], + 'browser_config': 'web-engine-shell', + 'os_type': 'linux', 'test_suites': { + 'gpu_telemetry_tests': 'fuchsia_gpu_telemetry_tests', 'gtest_tests': 'fuchsia_gtests', - 'isolated_scripts': 'gpu_angle_fuchsia_unittests_isolated_scripts', + 'isolated_scripts': 'fuchsia_isolated_scripts', }, 'mixins': [ 'arm64', @@ -2876,7 +2879,7 @@ 'ios-asan': { 'mixins': [ 'enable_resultdb', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2891,7 +2894,7 @@ 'enable_resultdb', 'ios_output_disabled_tests', 'isolate_profile_data', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2904,7 +2907,7 @@ 'ios-simulator-cronet': { 'mixins': [ 'enable_resultdb', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2917,7 +2920,7 @@ 'ios-simulator-multi-window': { 'mixins': [ 'enable_resultdb', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2931,7 +2934,7 @@ 'mixins': [ 'enable_resultdb', 'ios_custom_webkit', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12e262', @@ -4832,7 +4835,7 @@ }, 'test_suites': { 'gtest_tests': 'fuchsia_gtests', - 'isolated_scripts': 'fuchsia_x64_isolated_scripts', + 'isolated_scripts': 'fuchsia_isolated_scripts', 'gpu_telemetry_tests': 'fuchsia_gpu_telemetry_tests', }, }, @@ -5119,7 +5122,7 @@ 'mixins': [ 'enable_resultdb', 'isolate_profile_data', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -5136,7 +5139,7 @@ 'mixins': [ 'enable_resultdb', 'isolate_profile_data', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -5152,7 +5155,7 @@ ], 'mixins': [ 'enable_resultdb', - 'mac_10.15_or_mac_11', + 'mac_11_x64', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 781f3ba..45ed5fe 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -487,23 +487,23 @@ ] } ], - "AndroidInProductHelpToolbarButtons_TabSwitcher": [ + "AndroidInProductHelpToolbarButtons": [ { "platforms": [ "android" ], "experiments": [ { - "name": "TabSwitcherButtonIphConfig", + "name": "Default_20210520", "params": { - "availability": ">=1", - "cohortFeatureName": "ToolbarIphAndroidCohort1", + "availability": ">=14", "event_trigger": "name:tab_switcher_iph_triggered;comparator:==0;window:90;storage:90", "event_used": "name:tab_switcher_button_clicked;comparator:==0;window:14;storage:90", "session_rate": "<1" }, "enable_features": [ - "IPH_TabSwitcherButton" + "IPH_TabSwitcherButton", + "ToolbarIphAndroid" ] } ] @@ -4171,25 +4171,6 @@ ] } ], - "IOSStartSurface": [ - { - "platforms": [ - "ios" - ], - "experiments": [ - { - "name": "ShrinkLogo", - "params": { - "ReturnToStartSurfaceInactiveDurationInSeconds": "0", - "shrink_logo": "true" - }, - "enable_features": [ - "StartSurface" - ] - } - ] - } - ], "IOSUMABackgroundSessions": [ { "platforms": [ @@ -7428,6 +7409,25 @@ ] } ], + "StartSurface": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "ShrinkLogo", + "params": { + "ReturnToStartSurfaceInactiveDurationInSeconds": "0", + "shrink_logo": "true" + }, + "enable_features": [ + "StartSurface" + ] + } + ] + } + ], "StorageServiceOutOfProcess": [ { "platforms": [
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 617fdf6..59c92ace 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -138,7 +138,7 @@ # This target does not come with most of its dependencies and is # only meant to be used by the resources shrinker. If you wish to use # this for other purposes, change buildCompileNoDeps in build.gradle. - visibility = [ "//build/android/gyp/resources_shrinker:*" ] + visibility = [ "//build/android/unused_resources:*" ] } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. @@ -150,7 +150,7 @@ # This target does not come with most of its dependencies and is # only meant to be used by the resources shrinker. If you wish to use # this for other purposes, change buildCompileNoDeps in build.gradle. - visibility = [ "//build/android/gyp/resources_shrinker:*" ] + visibility = [ "//build/android/unused_resources:*" ] } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. @@ -162,7 +162,7 @@ # This target does not come with most of its dependencies and is # only meant to be used by the resources shrinker. If you wish to use # this for other purposes, change buildCompileNoDeps in build.gradle. - visibility = [ "//build/android/gyp/resources_shrinker:*" ] + visibility = [ "//build/android/unused_resources:*" ] } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index f7c0fb16..2ca87fa9 100644 --- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -655,7 +655,7 @@ sb.append(' # This target does not come with most of its dependencies and is\n') sb.append(' # only meant to be used by the resources shrinker. If you wish to use\n') sb.append(' # this for other purposes, change buildCompileNoDeps in build.gradle.\n') - sb.append(' visibility = [ "//build/android/gyp/resources_shrinker:*" ]\n') + sb.append(' visibility = [ "//build/android/unused_resources:*" ]\n') break case 'org_jetbrains_kotlinx_kotlinx_coroutines_android': sb.append('requires_android = true')
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h index 6826455..ba0b377 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h
@@ -143,6 +143,7 @@ class WebSecurityOrigin; class WebThemeEngine; class WebVideoCaptureImplManager; +struct WebContentSecurityPolicyHeader; namespace scheduler { class WebThreadScheduler; @@ -867,6 +868,14 @@ return nullptr; } + // Content Security Policy -------------------------------------- + + // Appends to `csp`, the default CSP which should be applied to the given + // `url`. This allows the embedder to customize the applied CSP. + virtual void AppendContentSecurityPolicy( + const WebURL& url, + blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) {} + private: static void InitializeMainThreadCommon(Platform* platform, std::unique_ptr<Thread> main_thread);
diff --git a/third_party/blink/public/platform/web_vector.h b/third_party/blink/public/platform/web_vector.h index c7d72275c..b8df4922 100644 --- a/third_party/blink/public/platform/web_vector.h +++ b/third_party/blink/public/platform/web_vector.h
@@ -171,6 +171,9 @@ data_.emplace_back(std::forward<Args>(args)...); } + void push_back(const T& value) { data_.push_back(value); } + void push_back(T&& value) { data_.push_back(std::move(value)); } + void Swap(WebVector<T>& other) { data_.swap(other.data_); } void Clear() { data_.clear(); }
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 33c1963a..5fd2955 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -9,7 +9,6 @@ from . import name_style from .blink_v8_bridge import blink_class_name from .blink_v8_bridge import blink_type_info -from .blink_v8_bridge import make_default_value_expr from .blink_v8_bridge import make_v8_to_blink_value from .blink_v8_bridge import make_v8_to_blink_value_variadic from .blink_v8_bridge import native_value_tag @@ -97,25 +96,9 @@ def callback_function_name(cg_context, overload_index=None, - argument_count=None, for_cross_origin=False): - """ - Args: - cg_context: A CodeGenContext of the target IDL construct. - overload_index: An overload index if the target is an overloaded - IDL operation. - argument_count: When the target is an IDL operation that has optional - arguments and is annotated with [NoAllocDirectCall], the value is - the number of arguments that V8 passes in (excluding the fixed - arguments like the receiver object and the - v8::FastApiCallbackOptions.) - for_cross_origin: True if the target is the cross origin accessible - version. - """ - assert isinstance(cg_context, CodeGenContext) assert overload_index is None or isinstance(overload_index, int) - assert argument_count is None or isinstance(argument_count, int) assert isinstance(for_cross_origin, bool) def _cxx_name(name): @@ -166,24 +149,14 @@ elif cg_context.stringifier: kind = "Operation" - if cg_context.no_alloc_direct_call: - nadc = "NoAllocDirectCall" - elif cg_context.no_alloc_direct_call_for_testing: - nadc = "NoAllocDirectCallForTesting" - else: - nadc = "" - - overload = "" - if overload_index is not None and (len(cg_context.constructor_group - or cg_context.operation_group) > 1): - overload += "Overload{}".format(overload_index + 1) - if argument_count is not None: - overload += "Arg{}".format(argument_count) - if for_cross_origin: suffix = "CrossOrigin" - elif nadc or overload: - suffix = nadc + overload + elif overload_index is not None: + suffix = "Overload{}".format(overload_index + 1) + elif cg_context.no_alloc_direct_call: + suffix = "NoAllocDirectCallCallback" + elif cg_context.no_alloc_direct_call_for_testing: + suffix = "NoAllocDirectCallForTestingCallback" else: suffix = "Callback" @@ -2210,74 +2183,14 @@ return SequenceNode([named_ctor_def, EmptyNode(), func_def]) -def list_no_alloc_direct_call_callbacks(cg_context): - """ - Returns a list of [NoAllocDirectCall] callback functions to be registered - at V8, including all overloaded operations annotated with - [NoAllocDirectCall] and their variants of optional arguments. - - Example: - Given the following Web IDL fragments, - void f(DOMString); // (a) - [NoAllocDirectCall] void f(Node node); // (b) - [NoAllocDirectCall] void f(optional long a, optional long b); // (c) - the following callback functions should be generated, - void F(v8::Local<v8::Value> node); // (b) - void F(); // (c) - void F(int32_t a); // (c) - void F(int32_t a, int32_t b); // (c) - thus the following entries are returned. - [ - Entry(operation=(b), argument_count=1), # overload_index=2 - Entry(operation=(c), argument_count=2), # overload_index=3 - Entry(operation=(c), argument_count=1), # overload_index=3 - Entry(operation=(c), argument_count=0), # overload_index=3 - ] - """ - assert isinstance(cg_context, CodeGenContext) - - class Entry(object): - def __init__(self, operation, argument_count): - self.operation = operation - self.argument_count = argument_count - self.callback_name = callback_function_name( - cg_context, - overload_index=self.operation.overload_index, - argument_count=self.argument_count) - - entries = [] - for operation in cg_context.operation_group: - if "NoAllocDirectCall" not in operation.extended_attributes: - continue - for argument in reversed(operation.arguments): - entries.append(Entry(operation, argument.index + 1)) - if not argument.is_optional: - break - else: - entries.append(Entry(operation, 0)) - return entries - - -def make_no_alloc_direct_call_callback_def(cg_context, function_name, - argument_count): - """ - Args: - cg_context: A CodeGenContext of the target IDL construct. - function_name: The function name to be produced. - argument_count: The number of arguments that the produced function - takes, which may be different from the number of arguments of - the target cg_context.function_like due to optional arguments. - """ +def make_no_alloc_direct_call_callback_def(cg_context, function_name): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) - assert isinstance(argument_count, int) S = SymbolNode T = TextNode F = lambda *args, **kwargs: T(_format(*args, **kwargs)) - function_like = cg_context.function_like - class ArgumentInfo(object): def __init__(self, v8_type, v8_arg_name, blink_arg_name, symbol_node): self.v8_type = v8_type @@ -2299,9 +2212,7 @@ "auto&& {} = {};".format(blink_arg_name, v8_arg_name))) arg_list = [] - for argument in function_like.arguments: - if not (argument.index < argument_count): - break + for argument in cg_context.operation.arguments: blink_arg_name = name_style.arg_f("arg{}_{}", argument.index + 1, argument.identifier) v8_arg_name = name_style.arg_f("v8_arg{}_{}", argument.index + 1, @@ -2315,8 +2226,8 @@ map(lambda arg: "{} {}".format(arg.v8_type, arg.v8_arg_name), arg_list)) + ["v8::FastApiCallbackOptions& v8_arg_callback_options"]) - return_type = ("void" if function_like.return_type.is_void else - blink_type_info(function_like.return_type).value_t) + return_type = ("void" if cg_context.operation.return_type.is_void else + blink_type_info(cg_context.operation.return_type).value_t) func_def = CxxFuncDefNode(name=function_name, arg_decls=arg_decls, @@ -2355,20 +2266,6 @@ blink_arguments = list( map(lambda arg: "${{{}}}".format(arg.blink_arg_name), arg_list)) - # If there are following optional arguments with default values, append - # them filled with the default values. - for argument in function_like.arguments[argument_count:]: - if not argument.default_value: - break - blink_arg_name = name_style.arg_f("arg{}_{}", argument.index + 1, - argument.identifier) - default_expr = make_default_value_expr(argument.idl_type, - argument.default_value) - body.register_code_symbol( - S((blink_arg_name), - "auto&& {}{{{}}};".format(blink_arg_name, - default_expr.initializer_expr))) - blink_arguments.append("${{{}}}".format(blink_arg_name)) if cg_context.may_throw_exception: blink_arguments.append("${exception_state}") body.append( @@ -2421,10 +2318,10 @@ "v8::FastApiCallbackOptions ${v8_fast_api_callback_options}" " = v8::FastApiCallbackOptions::CreateForTesting(${isolate});")) scope.extend([ - F(("{}(${info}, ${v8_fast_api_callback_options});"), - callback_function_name( - cg_context.make_copy(no_alloc_direct_call_for_testing=True), - overload_index=cg_context.operation.overload_index)), + F( + "{}(${info}, ${v8_fast_api_callback_options});", + callback_function_name( + cg_context.make_copy(no_alloc_direct_call_for_testing=True))), CxxUnlikelyIfNode(cond="${blink_receiver}->HasDeferredActions()", body=[ T("${blink_receiver}->FlushDeferredActions();"), @@ -2436,7 +2333,6 @@ return ListNode([ T("#if DCHECK_IS_ON()"), - T("// [NoAllocDirectCall]"), CxxUnlikelyIfNode(cond=("RuntimeEnabledFeatures::" "FakeNoAllocDirectCallForTestingEnabled()"), body=scope), @@ -2450,15 +2346,12 @@ if "NoAllocDirectCall" not in cg_context.operation.extended_attributes: return None - return SequenceNode([ - TextNode("// [NoAllocDirectCall]"), - CxxUnlikelyIfNode( - cond="UNLIKELY(${blink_receiver}->HasDeferredActions())", - body=[ - TextNode("${blink_receiver}->FlushDeferredActions();"), - TextNode("return;"), - ]), - ]) + return CxxUnlikelyIfNode( + cond="UNLIKELY(${blink_receiver}->HasDeferredActions())", + body=[ + TextNode("${blink_receiver}->FlushDeferredActions();"), + TextNode("return;"), + ]) def make_operation_entry(cg_context): @@ -2489,6 +2382,8 @@ make_report_measure_as(cg_context), make_log_activity(cg_context), EmptyNode(), + make_no_alloc_direct_call_flush_deferred_actions(cg_context), + EmptyNode(), ]) if "Custom" in cg_context.property_.extended_attributes: @@ -2498,8 +2393,6 @@ return func_def body.extend([ - make_no_alloc_direct_call_flush_deferred_actions(cg_context), - EmptyNode(), make_check_argument_length(cg_context), EmptyNode(), make_steps_of_ce_reactions(cg_context), @@ -2514,7 +2407,9 @@ return func_def -def make_operation_callback_def(cg_context, function_name): +def make_operation_callback_def(cg_context, + function_name, + no_alloc_direct_callback_name=None): assert isinstance(cg_context, CodeGenContext) assert isinstance(function_name, str) @@ -2522,54 +2417,48 @@ assert (not ("Custom" in operation_group.extended_attributes) or len(operation_group) == 1) + assert (not ("NoAllocDirectCall" in operation_group.extended_attributes) + or len(operation_group) == 1) - nodes = SequenceNode() if "NoAllocDirectCall" in operation_group.extended_attributes: - for entry in list_no_alloc_direct_call_callbacks(cg_context): - cgc = cg_context.make_copy(operation=entry.operation, - no_alloc_direct_call=True) - nodes.extend([ - make_no_alloc_direct_call_callback_def( - cgc, - callback_function_name( - cgc, - overload_index=entry.operation.overload_index, - argument_count=entry.argument_count), - argument_count=entry.argument_count), - EmptyNode(), - ]) - for operation in operation_group: - if "NoAllocDirectCall" not in operation.extended_attributes: - continue - cgc = cg_context.make_copy(operation=operation, - no_alloc_direct_call_for_testing=True) - nodes.extend([ - make_no_alloc_direct_call_for_testing_callback_def( - cgc, - callback_function_name( - cgc, overload_index=operation.overload_index)), - EmptyNode(), - ]) - - if len(operation_group) == 1: - nodes.append( - make_operation_function_def( - cg_context.make_copy(operation=operation_group[0]), - function_name)) + nodes = ListNode() + cgc = cg_context.make_copy(operation=operation_group[0], + no_alloc_direct_call=True) + nodes.extend([ + make_no_alloc_direct_call_callback_def( + cgc, no_alloc_direct_callback_name), + EmptyNode(), + ]) + cgc = cg_context.make_copy(operation=operation_group[0], + no_alloc_direct_call_for_testing=True) + nodes.extend([ + make_no_alloc_direct_call_for_testing_callback_def( + cgc, callback_function_name(cgc)), + EmptyNode(), + ]) + cgc = cg_context.make_copy(operation=operation_group[0]) + nodes.extend([ + make_operation_function_def(cgc, function_name), + ]) return nodes + if len(operation_group) == 1: + return make_operation_function_def( + cg_context.make_copy(operation=operation_group[0]), function_name) + + node = SequenceNode() for operation in operation_group: cgc = cg_context.make_copy(operation=operation) - nodes.extend([ + node.extend([ make_operation_function_def( cgc, callback_function_name( cgc, overload_index=operation.overload_index)), EmptyNode(), ]) - nodes.append( + node.append( make_overload_dispatcher_function_def(cg_context, function_name)) - return nodes + return node def make_stringifier_callback_def(cg_context, function_name): @@ -4743,6 +4632,13 @@ return "unsigned(IDLMemberInstaller::FlagReceiverCheck::kCheck)" +def _make_property_entry_v8_c_function(entry): + if entry.no_alloc_direct_callback_name is None: + return None + return "v8::CFunction::MakeWithFallbackSupport({})".format( + entry.no_alloc_direct_callback_name) + + def _make_property_entry_v8_cached_accessor(property_): return "unsigned(V8PrivateProperty::CachedAccessor::{})".format( property_.extended_attributes.value_of("CachedAccessor") or "kNone") @@ -4790,20 +4686,20 @@ T = TextNode entry_nodes = [] - pattern = ("{{" - "\"{property_name}\", " - "{attribute_get_callback}, " - "{attribute_set_callback}, " - "{v8_property_attribute}, " - "{location}, " - "{world}, " - "{receiver_check}, " - "{cross_origin_check_for_get}, " - "{cross_origin_check_for_set}, " - "{v8_side_effect}, " - "{v8_cached_accessor}" - "}},") for entry in attribute_entries: + pattern = ("{{" + "\"{property_name}\", " + "{attribute_get_callback}, " + "{attribute_set_callback}, " + "{v8_property_attribute}, " + "{location}, " + "{world}, " + "{receiver_check}, " + "{cross_origin_check_for_get}, " + "{cross_origin_check_for_set}, " + "{v8_side_effect}, " + "{v8_cached_accessor}" + "}},") text = _format( pattern, property_name=entry.property_.identifier, @@ -4846,12 +4742,8 @@ T = TextNode entry_nodes = [] - pattern = ( - "{{" # - "\"{property_name}\", " - "{constant_callback}" - "}},") for entry in constant_entries: + pattern = ("{{" "\"{property_name}\", " "{constant_callback}" "}},") text = _format( pattern, property_name=entry.property_.identifier, @@ -4876,12 +4768,11 @@ T = TextNode entry_nodes = [] - pattern = ( - "{{" # - "\"{property_name}\", " - "{constant_value}" - "}},") for entry in constant_entries: + pattern = ("{{" + "\"{property_name}\", " + "{constant_value}" + "}},") text = _format(pattern, property_name=entry.property_.identifier, constant_value=entry.const_constant_name) @@ -4932,51 +4823,30 @@ for entry in operation_entries) T = TextNode - F = lambda *args, **kwargs: T(_format(*args, **kwargs)) - no_alloc_direct_call_count = len( - list( - filter(lambda entry: entry.no_alloc_direct_call_callbacks, - operation_entries))) + no_alloc_direct_call_count = 0 + for entry in operation_entries: + if entry.no_alloc_direct_callback_name: + no_alloc_direct_call_count += 1 assert (no_alloc_direct_call_count == 0 or no_alloc_direct_call_count == len(operation_entries)) - no_alloc_direct_call_enabled = bool(no_alloc_direct_call_count) + no_alloc_direct_call_enabled = no_alloc_direct_call_count > 0 entry_nodes = [] - nadc_overload_nodes = ListNode() - pattern = ("{{" - "\"{property_name}\", " - "{operation_callback}, " - "{function_length}, " - "{v8_property_attribute}, " - "{location}, " - "{world}, " - "{receiver_check}, " - "{cross_origin_check}, " - "{v8_side_effect}" - "}}, ") - if no_alloc_direct_call_enabled: - pattern = ("{{" + pattern + "{v8_cfunction_table}, " - "base::size({v8_cfunction_table})}}, ") for entry in operation_entries: + pattern = ("{{" + "\"{property_name}\", " + "{operation_callback}, " + "{function_length}, " + "{v8_property_attribute}, " + "{location}, " + "{world}, " + "{receiver_check}, " + "{cross_origin_check}, " + "{v8_side_effect}" + "}}, ") if no_alloc_direct_call_enabled: - nadc_overload_table_name = name_style.constant( - "no_alloc_direct_call_overloads_of_", - entry.property_.identifier) - nadc_overload_nodes.append( - ListNode([ - T("static const v8::CFunction " + - nadc_overload_table_name + "[] = {"), - ListNode([ - F("v8::CFunctionBuilder().Fn({}).Build(),", - nadc_entry.callback_name) - for nadc_entry in entry.no_alloc_direct_call_callbacks - ]), - T("};"), - ])) - else: - nadc_overload_table_name = None - + pattern = "{{" + pattern + "{v8_c_function}}}, " text = _format( pattern, property_name=entry.property_.identifier, @@ -4992,7 +4862,7 @@ entry.property_), v8_side_effect=_make_property_entry_v8_side_effect( entry.property_), - v8_cfunction_table=nadc_overload_table_name) + v8_c_function=_make_property_entry_v8_c_function(entry)) entry_nodes.append(T(text)) table_decl_before_name = ( @@ -5001,18 +4871,11 @@ table_decl_before_name = ( "static const " "IDLMemberInstaller::NoAllocDirectCallOperationConfig") - node = ListNode() - if nadc_overload_nodes: - node.extend([ - nadc_overload_nodes, - EmptyNode(), - ]) - node.extend([ + return ListNode([ T(table_decl_before_name + " " + table_name + "[] = {"), ListNode(entry_nodes), T("};"), ]) - return node class _PropEntryBase(object): @@ -5081,7 +4944,7 @@ operation_group, op_callback_name, op_func_length, - no_alloc_direct_call_callbacks=None): + no_alloc_direct_callback_name=None): assert isinstance(op_callback_name, str) assert isinstance(op_func_length, int) @@ -5089,7 +4952,7 @@ exposure_conditional, world, operation_group) self.op_callback_name = op_callback_name self.op_func_length = op_func_length - self.no_alloc_direct_call_callbacks = no_alloc_direct_call_callbacks + self.no_alloc_direct_callback_name = no_alloc_direct_callback_name def make_property_entries_and_callback_defs(cg_context, attribute_entries, @@ -5290,12 +5153,14 @@ cgc = cg_context.make_copy( operation_group=operation_group, for_world=world) op_callback_name = callback_function_name(cgc) - op_callback_node = make_operation_callback_def(cgc, op_callback_name) - no_alloc_direct_call_callbacks = ( - list_no_alloc_direct_call_callbacks( - cgc.make_copy(no_alloc_direct_call=True)) + no_alloc_direct_callback_name = ( + callback_function_name(cgc.make_copy(no_alloc_direct_call=True)) if "NoAllocDirectCall" in operation_group.extended_attributes else None) + op_callback_node = make_operation_callback_def( + cgc, + op_callback_name, + no_alloc_direct_callback_name=no_alloc_direct_callback_name) callback_def_nodes.extend([ op_callback_node, @@ -5310,7 +5175,7 @@ operation_group=operation_group, op_callback_name=op_callback_name, op_func_length=operation_group.min_num_of_required_arguments, - no_alloc_direct_call_callbacks=no_alloc_direct_call_callbacks)) + no_alloc_direct_callback_name=no_alloc_direct_callback_name)) def process_stringifier(_, is_context_dependent, exposure_conditional, world): @@ -6042,12 +5907,12 @@ install_func="IDLMemberInstaller::InstallOperations", table_name=table_name) entries = list( - filter(lambda entry: not entry.no_alloc_direct_call_callbacks, + filter(lambda entry: not entry.no_alloc_direct_callback_name, operation_entries)) install_properties(table_name, entries, _make_operation_registration_table, installer_call_text) entries = list( - filter(lambda entry: entry.no_alloc_direct_call_callbacks, + filter(lambda entry: entry.no_alloc_direct_callback_name, operation_entries)) install_properties(table_name, entries, _make_operation_registration_table, installer_call_text)
diff --git a/third_party/blink/renderer/build/scripts/core/css/templates/css_value_keywords.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/templates/css_value_keywords.h.tmpl index 4cada5c..b254d4b3 100644 --- a/third_party/blink/renderer/build/scripts/core/css/templates/css_value_keywords.h.tmpl +++ b/third_party/blink/renderer/build/scripts/core/css/templates/css_value_keywords.h.tmpl
@@ -8,6 +8,7 @@ #include <string.h> #include <stdint.h> +#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h" namespace blink { @@ -27,7 +28,7 @@ return id != CSSValueID::kInvalid; } -const char* getValueName(CSSValueID); +CORE_EXPORT const char* getValueName(CSSValueID); bool isValueAllowedInMode(CSSValueID id, CSSParserMode mode); } // namespace blink
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 5c50c4d..b601c941 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1341,7 +1341,6 @@ "layout/layout_box_test.cc", "layout/layout_embedded_content_test.cc", "layout/layout_flexible_box_test.cc", - "layout/layout_grid_test.cc", "layout/layout_image_test.cc", "layout/layout_inline_test.cc", "layout/layout_list_marker_test.cc",
diff --git a/third_party/blink/renderer/core/dom/pseudo_element_data.h b/third_party/blink/renderer/core/dom/pseudo_element_data.h index 73a78bc..5196b24 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element_data.h +++ b/third_party/blink/renderer/core/dom/pseudo_element_data.h
@@ -55,35 +55,34 @@ inline void PseudoElementData::SetPseudoElement(PseudoId pseudo_id, PseudoElement* element) { + PseudoElement* previous_element = nullptr; switch (pseudo_id) { case kPseudoIdBefore: - if (generated_before_) - generated_before_->Dispose(); + previous_element = generated_before_; generated_before_ = element; break; case kPseudoIdAfter: - if (generated_after_) - generated_after_->Dispose(); + previous_element = generated_after_; generated_after_ = element; break; case kPseudoIdMarker: - if (generated_marker_) - generated_marker_->Dispose(); + previous_element = generated_marker_; generated_marker_ = element; break; case kPseudoIdBackdrop: - if (backdrop_) - backdrop_->Dispose(); + previous_element = backdrop_; backdrop_ = element; break; case kPseudoIdFirstLetter: - if (generated_first_letter_) - generated_first_letter_->Dispose(); + previous_element = generated_first_letter_; generated_first_letter_ = element; break; default: NOTREACHED(); } + + if (previous_element) + previous_element->Dispose(); } inline PseudoElement* PseudoElementData::GetPseudoElement(
diff --git a/third_party/blink/renderer/core/frame/use_counter_impl_test.cc b/third_party/blink/renderer/core/frame/use_counter_impl_test.cc index 70b081d..12bdc4a 100644 --- a/third_party/blink/renderer/core/frame/use_counter_impl_test.cc +++ b/third_party/blink/renderer/core/frame/use_counter_impl_test.cc
@@ -261,100 +261,6 @@ EXPECT_FALSE(document.IsUseCounted(feature)); } -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight1) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: 50%;'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_TRUE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight2) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: 50% 50%;'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_TRUE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight3) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: 100% 100%;'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_TRUE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight4) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: minmax(50%, " - "100%);'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_TRUE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight5) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; max-height: 0; grid-template-rows: " - "100%;'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_TRUE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight6) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: 100%;'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_FALSE(document.IsUseCounted(feature)); -} - -TEST_F(UseCounterImplTest, CSSGridLayoutPercentageRowIndefiniteHeight7) { - auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); - Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); - Document& document = dummy_page_holder->GetDocument(); - WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight; - EXPECT_FALSE(document.IsUseCounted(feature)); - document.documentElement()->setInnerHTML( - "<div style='display: inline-grid; grid-template-rows: minmax(100%, " - "100%);'>" - "</div>"); - UpdateAllLifecyclePhases(document); - EXPECT_FALSE(document.IsUseCounted(feature)); -} - TEST_F(UseCounterImplTest, CSSFlexibleBox) { auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
diff --git a/third_party/blink/renderer/core/layout/layout_grid_test.cc b/third_party/blink/renderer/core/layout/layout_grid_test.cc deleted file mode 100644 index 69120c92..0000000 --- a/third_party/blink/renderer/core/layout/layout_grid_test.cc +++ /dev/null
@@ -1,38 +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 "third_party/blink/renderer/core/testing/core_unit_test_helper.h" - -namespace blink { - -class LayoutGridTest : public RenderingTest {}; - -TEST_F(LayoutGridTest, RowGapUseCounter) { - SetBodyInnerHTML(R"HTML( - <div style="display: grid; gap: 20%;"> - <div></div> - <div></div> - </div> - )HTML"); - RunDocumentLifecycle(); - - EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kGridRowGapPercent)); - EXPECT_TRUE( - GetDocument().IsUseCounted(WebFeature::kGridRowGapPercentIndefinite)); -} - -TEST_F(LayoutGridTest, RowGapUseCounterOneTrack) { - SetBodyInnerHTML(R"HTML( - <div style="display: grid; gap: 20%;"> - <div></div> - </div> - )HTML"); - RunDocumentLifecycle(); - - EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kGridRowGapPercent)); - EXPECT_FALSE( - GetDocument().IsUseCounted(WebFeature::kGridRowGapPercentIndefinite)); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index d6323b2..71ec9eb 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -644,6 +644,13 @@ return ShouldApplyPaintContainment() && ShouldApplyLayoutContainment() && ShouldApplySizeContainment(); } + inline bool ShouldApplyAnyContainment() const { + NOT_DESTROYED(); + return ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() || + ShouldApplyStyleContainment() || ShouldApplyBlockSizeContainment() || + ShouldApplyInlineSizeContainment(); + } + inline bool IsContainerForContainerQueries() const { NOT_DESTROYED(); return ShouldApplyLayoutContainment() && ShouldApplyStyleContainment() &&
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 7af143b8..492a9d65 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
@@ -29,6 +29,26 @@ grid_available_size_ = grid_min_available_size_ = grid_max_available_size_ = ChildAvailableSize(); + // Firstly if block-size containment applies compute the block-size ignoring + // children (just based on the row definitions). + if (grid_available_size_.block_size == kIndefiniteSize && + Node().ShouldApplyBlockSizeContainment()) { + // We always need a definite min block-size in order to run the track + // sizing algorithm. + grid_min_available_size_.block_size = BorderScrollbarPadding().BlockSum(); + contain_intrinsic_block_size_ = ComputeIntrinsicBlockSizeIgnoringChildren(); + + // Resolve the block-size, and set the available sizes. + const LayoutUnit block_size = ComputeBlockSizeForFragment( + ConstraintSpace(), Style(), BorderPadding(), + *contain_intrinsic_block_size_, border_box_size_.inline_size); + + grid_available_size_.block_size = grid_min_available_size_.block_size = + grid_max_available_size_.block_size = + (block_size - BorderScrollbarPadding().BlockSum()) + .ClampNegativeToZero(); + } + // Next if our inline-size is indefinite, compute the min/max inline-sizes. if (grid_available_size_.inline_size == kIndefiniteSize) { const LayoutUnit border_scrollbar_padding = @@ -183,28 +203,29 @@ ComputeGrid(); - // Intrinsic block size is based on the final row offset. Because gutters - // are included in row offsets, subtract out the final gutter (if present). - LayoutUnit intrinsic_block_size = - grid_geometry.row_geometry.sets.back().offset - - grid_geometry.row_geometry.FinalGutterSize() + - BorderScrollbarPadding().block_end; + LayoutUnit intrinsic_block_size; + if (contain_intrinsic_block_size_) { + intrinsic_block_size = *contain_intrinsic_block_size_; + } else { + // Intrinsic block size is based on the final row offset. Because gutters + // are included in row offsets, subtract out the final gutter (if present). + intrinsic_block_size = grid_geometry.row_geometry.sets.back().offset - + grid_geometry.row_geometry.FinalGutterSize() + + BorderScrollbarPadding().block_end; - // TODO(layout-dev): This isn't great but matches legacy. Ideally this would - // only apply when we have only flexible track(s). - if (grid_items.IsEmpty() && Node().HasLineIfEmpty()) { + // TODO(layout-dev): This isn't great but matches legacy. Ideally this + // would only apply when we have only flexible track(s). + if (grid_items.IsEmpty() && Node().HasLineIfEmpty()) { + intrinsic_block_size = + std::max(intrinsic_block_size, BorderScrollbarPadding().BlockSum() + + Node().EmptyLineBlockSize()); + } + intrinsic_block_size = - std::max(intrinsic_block_size, BorderScrollbarPadding().BlockSum() + - Node().EmptyLineBlockSize()); + ClampIntrinsicBlockSize(ConstraintSpace(), Node(), + BorderScrollbarPadding(), intrinsic_block_size); } - // TODO(layout-dev): ClampIntrinsicBlockSize might not be correct for grid. - // Specifically do we need to run the sizing algorithm assuming no children - // for size containment. - intrinsic_block_size = - ClampIntrinsicBlockSize(ConstraintSpace(), Node(), - BorderScrollbarPadding(), intrinsic_block_size); - const LayoutUnit block_size = ComputeBlockSizeForFragment( ConstraintSpace(), container_style, BorderPadding(), intrinsic_block_size, border_box_size_.inline_size); @@ -318,15 +339,22 @@ MinMaxSizesResult NGGridLayoutAlgorithm::ComputeMinMaxSizes( const MinMaxSizesFloatInput&) const { - // TODO(janewman): Handle the cases typically done via: - // CalculateMinMaxSizesIgnoringChildren. + const LayoutUnit override_intrinsic_inline_size = + Node().OverrideIntrinsicContentInlineSize(); + if (override_intrinsic_inline_size != kIndefiniteSize) { + MinMaxSizes sizes; + sizes = + BorderScrollbarPadding().InlineSum() + override_intrinsic_inline_size; + return MinMaxSizesResult{sizes, + /* depends_on_block_constraints */ false}; + } - // Measure items. + // Measure items. If we have inline size containment, ignore all children. GridItems grid_items; - ConstructAndAppendGridItems(&grid_items); + if (!Node().ShouldApplyInlineSizeContainment()) + ConstructAndAppendGridItems(&grid_items); - const auto& container_style = Style(); - NGGridPlacement grid_placement(container_style, + NGGridPlacement grid_placement(Style(), ComputeAutomaticRepetitions(kForColumns), ComputeAutomaticRepetitions(kForRows)); @@ -860,6 +888,47 @@ } } +LayoutUnit NGGridLayoutAlgorithm::ComputeIntrinsicBlockSizeIgnoringChildren() + const { + DCHECK(Node().ShouldApplyBlockSizeContainment()); + + // First check 'contain-intrinsic-size'. + const LayoutUnit override_intrinsic_block_size = + Node().OverrideIntrinsicContentBlockSize(); + if (override_intrinsic_block_size != kIndefiniteSize) + return BorderScrollbarPadding().BlockSum() + override_intrinsic_block_size; + + // Don't append any children for this calculation. + GridItems grid_items; + NGGridPlacement grid_placement(Style(), + ComputeAutomaticRepetitions(kForColumns), + ComputeAutomaticRepetitions(kForRows)); + + // Build block track collections. + NGGridBlockTrackCollection column_block_track_collection(kForColumns); + NGGridBlockTrackCollection row_block_track_collection(kForRows); + BuildBlockTrackCollections(&grid_items, &column_block_track_collection, + &row_block_track_collection, &grid_placement); + + // Build algorithm row track collection from the block track collection. + NGGridLayoutAlgorithmTrackCollection row_track_collection( + row_block_track_collection, + grid_available_size_.block_size == kIndefiniteSize); + + GridGeometry grid_geometry(SetGeometry(), + InitializeTrackSizes(&row_track_collection)); + + // Resolve the rows. + bool unused_needs_additional_pass = false; + grid_geometry.row_geometry = ComputeUsedTrackSizes( + SizingConstraint::kLayout, grid_geometry, &row_track_collection, + &grid_items, &unused_needs_additional_pass); + + return grid_geometry.row_geometry.sets.back().offset - + grid_geometry.row_geometry.FinalGutterSize() + + BorderScrollbarPadding().block_end; +} + LayoutUnit NGGridLayoutAlgorithm::ContributionSizeForGridItem( const GridGeometry& grid_geometry, const GridItemData& grid_item, @@ -883,7 +952,25 @@ ComputeMarginsFor(space, node.Style(), ConstraintSpace()); auto MinMaxContentSizes = [&]() -> MinMaxSizes { - return ComputeMinAndMaxContentContributionForSelf(node, space).sizes; + const auto result = ComputeMinAndMaxContentContributionForSelf(node, space); + + // The min/max contribution may depend on the block-size of the grid-area: + // <div style="display: inline-grid; grid-template-columns: auto auto;"> + // <div style="height: 100%"> + // <img style="height: 50%;" /> + // </div> + // <div> + // <div style="height: 100px;"></div> + // </div> + // </div> + // Mark ourselves as requiring an additional pass to re-resolve the column + // tracks for this case. + if (is_parallel && result.depends_on_block_constraints && + space.AvailableSize().block_size == kIndefiniteSize) { + *needs_additional_pass = true; + } + + return result.sizes; }; // This function will determine the correct block-size of a grid-item.
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h index 3872e0b..4c957227 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -315,6 +315,8 @@ enum class SizingConstraint { kLayout, kMinContent, kMaxContent }; + LayoutUnit ComputeIntrinsicBlockSizeIgnoringChildren() const; + // Returns the size that a grid item will distribute across the tracks with an // intrinsic sizing function it spans in the relevant track direction. LayoutUnit ContributionSizeForGridItem( @@ -497,6 +499,8 @@ LogicalSize grid_available_size_; LogicalSize grid_min_available_size_; LogicalSize grid_max_available_size_; + + absl::optional<LayoutUnit> contain_intrinsic_block_size_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc index f980874..8ddbfb7 100644 --- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc +++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" +#include "third_party/blink/renderer/core/layout/svg/svg_resources.h" #include "third_party/blink/renderer/core/svg/svg_text_element.h" namespace blink { @@ -19,6 +20,19 @@ DCHECK(IsA<SVGTextElement>(element)); } +void LayoutNGSVGText::StyleDidChange(StyleDifference diff, + const ComputedStyle* old_style) { + NOT_DESTROYED(); + LayoutNGBlockFlowMixin<LayoutSVGBlock>::StyleDidChange(diff, old_style); + SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef()); +} + +void LayoutNGSVGText::WillBeDestroyed() { + NOT_DESTROYED(); + SVGResources::ClearPaints(*GetElement(), Style()); + LayoutNGBlockFlowMixin<LayoutSVGBlock>::WillBeDestroyed(); +} + const char* LayoutNGSVGText::GetName() const { NOT_DESTROYED(); return "LayoutNGSVGText";
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h index abc5607..8a8875a 100644 --- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h +++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h
@@ -32,6 +32,8 @@ FloatRect ObjectBoundingBox() const override; FloatRect StrokeBoundingBox() const override; FloatRect VisualRectInLocalSVGCoordinates() const override; + void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override; + void WillBeDestroyed() override; // LayoutBox override: bool CreatesNewFormattingContext() const override;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc index 9994752..c2789b0d 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.cc
@@ -39,16 +39,23 @@ *inline_size = LayoutUnit(length.Value()); if (is_content_box) *inline_size = **inline_size + inline_border_padding; + else + *inline_size = std::max(**inline_size, inline_border_padding); } if (min_length.IsFixed()) { *min_inline_size = LayoutUnit(min_length.Value()); if (is_content_box) *min_inline_size = **min_inline_size + inline_border_padding; + else + *min_inline_size = std::max(**min_inline_size, inline_border_padding); } if (max_length.IsFixed()) { *max_inline_size = LayoutUnit(max_length.Value()); if (is_content_box) *max_inline_size = **max_inline_size + inline_border_padding; + else + *max_inline_size = std::max(**max_inline_size, inline_border_padding); + if (*min_inline_size) *max_inline_size = std::max(**min_inline_size, **max_inline_size); }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 275d61d6..2311e161 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -43,6 +43,8 @@ #include "third_party/blink/public/mojom/commit_result/commit_result.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/public/platform/web_content_security_policy_struct.h" #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/renderer/core/app_history/app_history.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -2665,6 +2667,15 @@ policy_container_->AddContentSecurityPolicies(mojo::Clone(parsed_policies)); csp->AddPolicies(std::move(parsed_policies)); + // Check if the embedder wants to add any default policies, and add them. + WebVector<WebContentSecurityPolicyHeader> embedder_default_csp; + Platform::Current()->AppendContentSecurityPolicy(WebURL(Url()), + &embedder_default_csp); + for (const auto& header : embedder_default_csp) { + csp->AddPolicies(ParseContentSecurityPolicies( + header.header_value, header.type, header.source, Url())); + } + // Retrieve CSP stored in the OriginPolicy and add them to the policy // container. if (origin_policy_) {
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc index 644524a1..f289caede 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -34,6 +34,7 @@ #include <memory> #include "base/feature_list.h" +#include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "net/http/structured_headers.h" @@ -801,7 +802,16 @@ const absl::optional<ResourceRequest::RedirectInfo>& redirect_info, ReportingDisposition reporting_disposition, const String& devtools_request_id) const { - if (GetResourceFetcherProperties().IsDetached()) + const char kWellKnownConversionRegistrationPath[] = + "/.well-known/attribution-reporting/trigger-attribution"; + if (url.GetPath() != kWellKnownConversionRegistrationPath) + return false; + + const bool detached = GetResourceFetcherProperties().IsDetached(); + UMA_HISTOGRAM_BOOLEAN("Conversions.RedirectInterceptedFrameDetached", + detached); + + if (detached) return false; if (!RuntimeEnabledFeatures::ConversionMeasurementEnabled( @@ -815,11 +825,6 @@ return false; } - const char kWellKnownConversionRegsitrationPath[] = - "/.well-known/attribution-reporting/trigger-attribution"; - if (url.GetPath() != kWellKnownConversionRegsitrationPath) - return false; - if (!document_->domWindow()->IsFeatureEnabled( mojom::blink::PermissionsPolicyFeature::kAttributionReporting)) { AuditsIssue::ReportAttributionIssue(
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc index dd9ee9c..1d04c3d 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -1347,6 +1347,43 @@ net::SiteForCookies::FromUrl(document_url))); } +TEST_F(FrameFetchContextTest, + SendConversionRequestInsteadOfRedirecting_RecordsMetric) { + const bool kDetach = true; + const bool kNoDetach = false; + + const char kTriggerURL[] = + "https://www.example.com/.well-known/attribution-reporting/" + "trigger-attribution"; + const char kNoTriggerURL[] = "https://www.example.com/"; + + struct { + KURL url; + bool detach; + int want; + } test_cases[] = { + {KURL(kNoTriggerURL), kNoDetach, 0}, + {KURL(kTriggerURL), kNoDetach, 1}, + {KURL(kNoTriggerURL), kDetach, 0}, + {KURL(kTriggerURL), kDetach, 1}, + }; + + for (const auto& test_case : test_cases) { + if (test_case.detach) + dummy_page_holder = nullptr; + + HistogramTester histograms; + GetFetchContext()->SendConversionRequestInsteadOfRedirecting( + test_case.url, /*redirect_info=*/absl::nullopt, + ReportingDisposition::kReport, /*devtools_request_id=*/"abc"); + histograms.ExpectUniqueSample( + "Conversions.RedirectInterceptedFrameDetached", test_case.detach, + test_case.want); + + RecreateFetchContext(); + } +} + TEST_F(FrameFetchContextTest, TopFrameOrigin) { const KURL document_url("https://www2.example.com/foo/bar"); RecreateFetchContext(document_url);
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc index bacf27d..cc07bc2 100644 --- a/third_party/blink/renderer/core/messaging/message_port.cc +++ b/third_party/blink/renderer/core/messaging/message_port.cc
@@ -145,7 +145,7 @@ return; started_ = true; - connector_->ResumeIncomingMethodCallProcessing(); + connector_->StartReceiving(task_runner_); } void MessagePort::close() { @@ -168,8 +168,7 @@ port_ = std::move(port); connector_ = std::make_unique<mojo::Connector>( port_.TakeHandleToEntangle(GetExecutionContext()), - mojo::Connector::SINGLE_THREADED_SEND, task_runner_); - connector_->PauseIncomingMethodCallProcessing(); + mojo::Connector::SINGLE_THREADED_SEND); connector_->set_incoming_receiver(this); connector_->set_connection_error_handler( WTF::Bind(&MessagePort::close, WrapWeakPersistent(this)));
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc index 38e28ad..72c31017 100644 --- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc +++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -196,17 +196,6 @@ if (target_state == DocumentLifecycle::kCompositingInputsClean) return; - { - // TODO(szager): Remove this after diagnosing crash. - DisableCompositingQueryAsserts query_assert_disabler; - CHECK_EQ(InCompositingMode(), (bool)RootGraphicsLayer()); - if (auto* owner = layout_view_->GetFrame()->OwnerLayoutObject()) { - auto* parent_compositor = owner->View()->Compositor(); - CHECK(parent_compositor->StaleInCompositingMode() || - !RootGraphicsLayer()); - } - } - if (layout_view_->GetFrameView()->ShouldThrottleRendering()) return;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc index 3a6ef1b..3ef4c701 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -144,10 +144,14 @@ const LayoutObject* layout_object = text_item.GetLayoutObject(); const Document& document = layout_object->GetDocument(); const bool is_printing = document.Printing(); + // Don't paint selections when rendering a mask, clip-path (as a mask), + // pattern or feImage (element reference.) + const bool is_rendering_resource = paint_info.IsRenderingResourceSubtree(); // Determine whether or not we're selected. absl::optional<NGHighlightPainter::SelectionPaintState> selection; - if (UNLIKELY(!is_printing && paint_info.phase != PaintPhase::kTextClip && + if (UNLIKELY(!is_printing && !is_rendering_resource && + paint_info.phase != PaintPhase::kTextClip && layout_object->IsSelected())) { const NGInlineCursor& root_inline_cursor = InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_); @@ -238,14 +242,8 @@ // Determine text colors. Node* node = layout_object->GetNode(); - DCHECK(!svg_inline_text || - (!IsA<SVGElement>(node) && IsA<SVGElement>(node->parentNode()))); TextPaintStyle text_style = - svg_inline_text - ? TextPainterBase::SvgTextPaintingStyle( - document, SVGLengthContext(To<SVGElement>(node->parentNode())), - style, paint_info) - : TextPainterBase::TextPaintingStyle(document, style, paint_info); + TextPainterBase::TextPaintingStyle(document, style, paint_info); // TODO(crbug.com/1179585): Support SVG Paint Servers (e.g. Gradient, Pattern) if (UNLIKELY(selection)) { selection->ComputeSelectionStyle(document, style, node, paint_info, @@ -261,41 +259,55 @@ const bool paint_marker_backgrounds = paint_info.phase != PaintPhase::kSelectionDragImage && paint_info.phase != PaintPhase::kTextClip && !is_printing; - absl::optional<GraphicsContextStateSaver> state_saver; + GraphicsContextStateSaver state_saver(context, /*save_and_restore=*/false); absl::optional<AffineTransform> rotation; const WritingMode writing_mode = style.GetWritingMode(); const bool is_horizontal = IsHorizontalWritingMode(writing_mode); int ascent = font_data ? font_data->GetFontMetrics().Ascent() : 0; PhysicalOffset text_origin(box_rect.offset.left, box_rect.offset.top + ascent); - if (svg_inline_text && scaling_factor != 1.0f) { - state_saver.emplace(context); - context.Scale(1 / scaling_factor, 1 / scaling_factor); - } - if (text_item.HasSvgTransformForPaint()) { - if (!state_saver) - state_saver.emplace(context); - context.ConcatCTM(text_item.BuildSvgTransformForPaint()); - } + NGTextPainter text_painter(context, font, fragment_paint_info, visual_rect, text_origin, box_rect, is_horizontal); NGHighlightPainter highlight_painter( text_painter, paint_info, cursor_, *cursor_.CurrentItem(), box_rect.offset, style, std::move(selection), is_printing); + if (svg_inline_text) { + NGTextPainter::SvgTextPaintState& svg_state = text_painter.SetSvgState( + *svg_inline_text, style, paint_info.IsRenderingClipPathAsMaskImage()); + + if (scaling_factor != 1.0f) { + state_saver.SaveIfNeeded(); + context.Scale(1 / scaling_factor, 1 / scaling_factor); + svg_state.EnsureShaderTransform().Scale(scaling_factor); + } + if (text_item.HasSvgTransformForPaint()) { + state_saver.SaveIfNeeded(); + const auto fragment_transform = text_item.BuildSvgTransformForPaint(); + context.ConcatCTM(fragment_transform); + DCHECK(fragment_transform.IsInvertible()); + svg_state.EnsureShaderTransform().PreMultiply( + fragment_transform.Inverse()); + } + } + // 1. Paint backgrounds for document markers that don’t participate in the CSS // highlight overlay system, such as composition highlights. They use physical // coordinates, so are painted before GraphicsContext rotation. highlight_painter.Paint(NGHighlightPainter::kBackground); if (!is_horizontal) { - if (!state_saver) - state_saver.emplace(context); + state_saver.SaveIfNeeded(); // Because we rotate the GraphicsContext to match the logical direction, // transpose the |box_rect| to match to it. box_rect.size = PhysicalSize(box_rect.Height(), box_rect.Width()); rotation.emplace(TextPainterBase::Rotation(box_rect, writing_mode)); context.ConcatCTM(*rotation); + if (NGTextPainter::SvgTextPaintState* state = text_painter.GetSvgState()) { + DCHECK(rotation->IsInvertible()); + state->EnsureShaderTransform().PreMultiply(rotation->Inverse()); + } } if (UNLIKELY(highlight_painter.Selection())) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc index 318b6ffa..4b79acf 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -9,23 +9,108 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" #include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h" #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h" +#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h" +#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" +#include "third_party/blink/renderer/core/layout/svg/svg_resources.h" #include "third_party/blink/renderer/core/paint/applied_decoration_painter.h" #include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h" +#include "third_party/blink/renderer/core/paint/svg_object_painter.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/shadow_list.h" +#include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" namespace blink { namespace { +class SelectionStyleScope { + STACK_ALLOCATED(); + + public: + SelectionStyleScope(LayoutObject&, + const ComputedStyle& style, + const ComputedStyle& selection_style); + SelectionStyleScope(const SelectionStyleScope&) = delete; + SelectionStyleScope& operator=(const SelectionStyleScope) = delete; + ~SelectionStyleScope(); + + private: + LayoutObject& layout_object_; + const ComputedStyle& selection_style_; + const bool styles_are_equal_; +}; + +SelectionStyleScope::SelectionStyleScope(LayoutObject& layout_object, + const ComputedStyle& style, + const ComputedStyle& selection_style) + : layout_object_(layout_object), + selection_style_(selection_style), + styles_are_equal_(style == selection_style) { + if (styles_are_equal_) + return; + DCHECK(!layout_object.IsSVGInlineText()); + auto& element = To<SVGElement>(*layout_object_.GetNode()); + SVGResources::UpdatePaints(element, nullptr, selection_style_); +} + +SelectionStyleScope::~SelectionStyleScope() { + if (styles_are_equal_) + return; + auto& element = To<SVGElement>(*layout_object_.GetNode()); + SVGResources::ClearPaints(element, &selection_style_); +} + +bool SetupPaintForSvgText(const LayoutSVGInlineText& svg_inline_text, + const GraphicsContext& context, + bool is_rendering_clip_path_as_mask_image, + const ComputedStyle& style, + const AffineTransform* shader_transform, + LayoutSVGResourceMode resource_mode, + PaintFlags& flags) { + const LayoutObject* layout_parent = svg_inline_text.Parent(); + if (!SVGObjectPainter(*layout_parent) + .PreparePaint(context, is_rendering_clip_path_as_mask_image, style, + resource_mode, flags, shader_transform)) { + return false; + } + + flags.setAntiAlias(true); + + if (style.TextShadow() && + // Text shadows are disabled when printing. http://crbug.com/258321 + !svg_inline_text.GetDocument().Printing()) { + flags.setLooper(TextPainterBase::CreateDrawLooper( + style.TextShadow(), DrawLooperBuilder::kShadowRespectsAlpha, + style.VisitedDependentColor(GetCSSPropertyColor()), + style.UsedColorScheme())); + } + + if (resource_mode == kApplyToStrokeMode) { + // The stroke geometry needs be generated based on the scaled font. + float stroke_scale_factor = + style.VectorEffect() != EVectorEffect::kNonScalingStroke + ? svg_inline_text.ScalingFactor() + : 1; + StrokeData stroke_data; + SVGLayoutSupport::ApplyStrokeStyleToStrokeData( + stroke_data, style, *layout_parent, stroke_scale_factor); + if (stroke_scale_factor != 1) + stroke_data.SetThickness(stroke_data.Thickness() * stroke_scale_factor); + stroke_data.SetupPaint(&flags); + } + + return true; +} + absl::optional<TextDecorationInfo> DecorationsForLayer( const NGFragmentItem& text_item, const PhysicalRect& decoration_rect, @@ -87,6 +172,11 @@ // painting in most small text. snapped_selection_rect.Inflate(1); if (snapped_selection_rect.Contains(visual_rect_)) { + absl::optional<base::AutoReset<bool>> is_painting_selection_reset; + if (svg_text_paint_state_.has_value()) { + is_painting_selection_reset.emplace( + &svg_text_paint_state_->is_painting_selection_, true); + } Paint(start_offset, end_offset, length, selection_style, node_id); return; } @@ -109,6 +199,11 @@ } // Then draw the glyphs inside the selection area, with the selection style. { + absl::optional<base::AutoReset<bool>> is_painting_selection_reset; + if (svg_text_paint_state_.has_value()) { + is_painting_selection_reset.emplace( + &svg_text_paint_state_->is_painting_selection_, true); + } GraphicsContextStateSaver state_saver(graphics_context_); graphics_context_.Clip(float_selection_rect); Paint(start_offset, end_offset, length, selection_style, node_id); @@ -175,8 +270,12 @@ FloatPoint(text_origin_) + IntSize(0, emphasis_mark_offset_)); } else { DCHECK(step == kPaintText); - graphics_context_.DrawText(font_, fragment_paint_info_, - FloatPoint(text_origin_), node_id); + if (svg_text_paint_state_.has_value()) { + PaintSvgTextFragment(node_id); + } else { + graphics_context_.DrawText(font_, fragment_paint_info_, + FloatPoint(text_origin_), node_id); + } // TODO(npm): Check that there are non-whitespace characters. See // crbug.com/788444. graphics_context_.GetPaintController().SetTextPainted(); @@ -223,4 +322,113 @@ DecorationsStripeIntercepts(upper, stripe_width, dilation, text_intercepts); } +void NGTextPainter::PaintSvgTextFragment(DOMNodeId node_id) { + const NGTextPainter::SvgTextPaintState& state = *svg_text_paint_state_; + absl::optional<SelectionStyleScope> selection_style_scope; + bool has_fill = state.Style().HasFill(); + bool has_visible_stroke = state.Style().HasVisibleStroke(); + const ComputedStyle* style_to_paint = &state.Style(); + if (state.IsPaintingSelection()) { + LayoutObject* layout_parent = state.InlineText().Parent(); + style_to_paint = + layout_parent->GetCachedPseudoElementStyle(kPseudoIdSelection); + if (style_to_paint) { + if (!has_fill) + has_fill = style_to_paint->HasFill(); + if (!has_visible_stroke) + has_visible_stroke = style_to_paint->HasVisibleStroke(); + } else { + style_to_paint = &state.Style(); + } + + selection_style_scope.emplace(*layout_parent, state.Style(), + *style_to_paint); + } + + if (state.IsRenderingClipPathAsMaskImage()) { + has_fill = true; + has_visible_stroke = false; + } + + for (int i = 0; i < 3; i++) { + absl::optional<LayoutSVGResourceMode> resource_mode; + + switch (state.Style().PaintOrderType(i)) { + case PT_FILL: + if (has_fill) + resource_mode = kApplyToFillMode; + break; + case PT_STROKE: + if (has_visible_stroke) + resource_mode = kApplyToStrokeMode; + break; + case PT_MARKERS: + // Markers don't apply to text + break; + default: + NOTREACHED(); + break; + } + + if (resource_mode) { + PaintFlags flags; + if (SetupPaintForSvgText(state.InlineText(), graphics_context_, + state.IsRenderingClipPathAsMaskImage(), + *style_to_paint, state.GetShaderTransform(), + *resource_mode, flags)) { + graphics_context_.DrawText(font_, fragment_paint_info_, + FloatPoint(text_origin_), flags, node_id); + } + } + } +} + +NGTextPainter::SvgTextPaintState& NGTextPainter::SetSvgState( + const LayoutSVGInlineText& svg_inline_text, + const ComputedStyle& style, + bool is_rendering_clip_path_as_mask_image) { + return svg_text_paint_state_.emplace(svg_inline_text, style, + is_rendering_clip_path_as_mask_image); +} + +NGTextPainter::SvgTextPaintState* NGTextPainter::GetSvgState() { + return base::OptionalOrNullptr(svg_text_paint_state_); +} + +NGTextPainter::SvgTextPaintState::SvgTextPaintState( + const LayoutSVGInlineText& layout_svg_inline_text, + const ComputedStyle& style, + bool is_rendering_clip_path_as_mask_image) + : layout_svg_inline_text_(layout_svg_inline_text), + style_(style), + is_rendering_clip_path_as_mask_image_( + is_rendering_clip_path_as_mask_image) {} + +const LayoutSVGInlineText& NGTextPainter::SvgTextPaintState::InlineText() + const { + return layout_svg_inline_text_; +} + +const ComputedStyle& NGTextPainter::SvgTextPaintState::Style() const { + return style_; +} + +bool NGTextPainter::SvgTextPaintState::IsPaintingSelection() const { + return is_painting_selection_; +} + +bool NGTextPainter::SvgTextPaintState::IsRenderingClipPathAsMaskImage() const { + return is_rendering_clip_path_as_mask_image_; +} + +AffineTransform& NGTextPainter::SvgTextPaintState::EnsureShaderTransform() { + return shader_transform_ ? shader_transform_.value() + : shader_transform_.emplace(); +} + +const AffineTransform* NGTextPainter::SvgTextPaintState::GetShaderTransform() + const { + return base::OptionalOrNullptr(shader_transform_); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_painter.h b/third_party/blink/renderer/core/paint/ng/ng_text_painter.h index 6e0f965..26b4bb67 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_painter.h +++ b/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
@@ -12,6 +12,7 @@ namespace blink { +class LayoutSVGInlineText; class NGFragmentItem; struct NGTextFragmentPaintInfo; @@ -24,6 +25,29 @@ STACK_ALLOCATED(); public: + class SvgTextPaintState final { + public: + SvgTextPaintState(const LayoutSVGInlineText&, + const ComputedStyle&, + bool is_rendering_clip_path_as_mask_image); + + const LayoutSVGInlineText& InlineText() const; + const ComputedStyle& Style() const; + bool IsPaintingSelection() const; + bool IsRenderingClipPathAsMaskImage() const; + + AffineTransform& EnsureShaderTransform(); + const AffineTransform* GetShaderTransform() const; + + private: + const LayoutSVGInlineText& layout_svg_inline_text_; + const ComputedStyle& style_; + absl::optional<AffineTransform> shader_transform_; + bool is_painting_selection_ = false; + bool is_rendering_clip_path_as_mask_image_ = false; + friend class NGTextPainter; + }; + NGTextPainter(GraphicsContext& context, const Font& font, const NGTextFragmentPaintInfo& fragment_paint_info, @@ -75,6 +99,11 @@ const PhysicalRect& decoration_rect, const absl::optional<AppliedTextDecoration>& selection_decoration); + SvgTextPaintState& SetSvgState(const LayoutSVGInlineText&, + const ComputedStyle&, + bool is_rendering_clip_path_as_mask_image); + SvgTextPaintState* GetSvgState(); + private: template <PaintInternalStep step> void PaintInternalFragment(unsigned from, unsigned to, DOMNodeId node_id); @@ -85,8 +114,11 @@ unsigned truncation_point, DOMNodeId node_id); + void PaintSvgTextFragment(DOMNodeId node_id); + NGTextFragmentPaintInfo fragment_paint_info_; const IntRect& visual_rect_; + absl::optional<SvgTextPaintState> svg_text_paint_state_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 5809969..b1263e3 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -3479,31 +3479,32 @@ UpdateBackdropFilters(old_style, new_style); UpdateClipPath(old_style, new_style); - if (!SelfNeedsRepaint()) { - if (diff.ZIndexChanged()) { - // We don't need to invalidate paint of objects when paint order - // changes. However, we do need to repaint the containing stacking - // context, in order to generate new paint chunks in the correct order. - // Raster invalidation will be issued if needed during paint. - SetNeedsRepaint(); - } else if (old_style) { - bool new_painted_output_invisible = - PaintLayerPainter::PaintedOutputInvisible(new_style); - if (PaintLayerPainter::PaintedOutputInvisible(*old_style) != - new_painted_output_invisible) { - if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - // Though CompositeAfterPaint ignores PaintedOutputInvisible during - // paint, we still force repaint to ensure FCP/LCP will be reported. - // See crbug.com/1184903. Only SetNeedsRepaint() won't work because - // we won't repaint the display items which are already in the old - // painted result. TODO(crbug.com/1104218): Optimize this. - if (!new_painted_output_invisible) - GetLayoutObject().SetSubtreeShouldDoFullPaintInvalidation(); - } else { - // Change of PaintedOutputInvisible() will affect existence of paint - // chunks, so needs repaint. - SetNeedsRepaint(); - } + if (diff.ZIndexChanged()) { + // We don't need to invalidate paint of objects when paint order + // changes. However, we do need to repaint the containing stacking + // context, in order to generate new paint chunks in the correct order. + // Raster invalidation will be issued if needed during paint. + if (auto* stacking_context = AncestorStackingContext()) + stacking_context->SetNeedsRepaint(); + } + + if (old_style) { + bool new_painted_output_invisible = + PaintLayerPainter::PaintedOutputInvisible(new_style); + if (PaintLayerPainter::PaintedOutputInvisible(*old_style) != + new_painted_output_invisible) { + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { + // Though CompositeAfterPaint ignores PaintedOutputInvisible during + // paint, we still force repaint to ensure FCP/LCP will be reported. + // See crbug.com/1184903. Only SetNeedsRepaint() won't work because + // we won't repaint the display items which are already in the old + // painted result. TODO(crbug.com/1104218): Optimize this. + if (!new_painted_output_invisible) + GetLayoutObject().SetSubtreeShouldDoFullPaintInvalidation(); + } else { + // Change of PaintedOutputInvisible() will affect existence of paint + // chunks, so needs repaint. + SetNeedsRepaint(); } } }
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.cc b/third_party/blink/renderer/core/paint/text_painter_base.cc index 007c36e..313eba8 100644 --- a/third_party/blink/renderer/core/paint/text_painter_base.cc +++ b/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -13,7 +13,6 @@ #include "third_party/blink/renderer/core/paint/text_decoration_info.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/shadow_list.h" -#include "third_party/blink/renderer/core/svg/svg_length_context.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h" #include "third_party/blink/renderer/platform/geometry/length_functions.h" @@ -72,34 +71,6 @@ } // static -void TextPainterBase::AdjustTextStyleForClip(TextPaintStyle& text_style) { - // When we use the text as a clip, we only care about the alpha, thus we - // make all the colors black. - text_style.current_color = Color::kBlack; - text_style.fill_color = Color::kBlack; - text_style.stroke_color = Color::kBlack; - text_style.emphasis_mark_color = Color::kBlack; - text_style.shadow = nullptr; -} - -// static -void TextPainterBase::AdjustTextStyleForPrint(const Document& document, - const ComputedStyle& style, - TextPaintStyle& text_style) { - // Adjust text color when printing with a white background. - bool force_background_to_white = - BoxPainterBase::ShouldForceWhiteBackgroundForPrintEconomy(document, - style); - if (force_background_to_white) { - text_style.fill_color = TextColorForWhiteBackground(text_style.fill_color); - text_style.stroke_color = - TextColorForWhiteBackground(text_style.stroke_color); - text_style.emphasis_mark_color = - TextColorForWhiteBackground(text_style.emphasis_mark_color); - } -} - -// static void TextPainterBase::UpdateGraphicsContext( GraphicsContext& context, const TextPaintStyle& text_style, @@ -186,7 +157,13 @@ text_style.color_scheme = style.UsedColorScheme(); if (paint_info.phase == PaintPhase::kTextClip) { - AdjustTextStyleForClip(text_style); + // When we use the text as a clip, we only care about the alpha, thus we + // make all the colors black. + text_style.current_color = Color::kBlack; + text_style.fill_color = Color::kBlack; + text_style.stroke_color = Color::kBlack; + text_style.emphasis_mark_color = Color::kBlack; + text_style.shadow = nullptr; } else { text_style.current_color = style.VisitedDependentColor(GetCSSPropertyColor()); @@ -198,54 +175,18 @@ style.VisitedDependentColor(GetCSSPropertyWebkitTextEmphasisColor()); text_style.shadow = style.TextShadow(); - AdjustTextStyleForPrint(document, style, text_style); - } - - return text_style; -} - -// static -TextPaintStyle TextPainterBase::SvgTextPaintingStyle( - const Document& document, - const SVGLengthContext& length_context, - const ComputedStyle& style, - const PaintInfo& paint_info) { - TextPaintStyle text_style; - text_style.stroke_width = - style.HasStroke() ? length_context.ValueForLength(style.StrokeWidth()) - : 0; - text_style.color_scheme = style.UsedColorScheme(); - - if (paint_info.phase == PaintPhase::kTextClip) { - AdjustTextStyleForClip(text_style); - } else { - text_style.current_color = - style.VisitedDependentColor(GetCSSPropertyColor()); - - const SVGPaint fill_paint = style.FillPaint(); - if (fill_paint.IsNone()) { - text_style.fill_color = Color::kTransparent; - } else if (fill_paint.HasColor()) { - const Color color = style.VisitedDependentColor(GetCSSPropertyFill()); - const float alpha = style.FillOpacity(); - text_style.fill_color = ScaleAlpha(color.Rgb(), alpha); - } else { - text_style.fill_color = Color::kBlack; + // Adjust text color when printing with a white background. + bool force_background_to_white = + BoxPainterBase::ShouldForceWhiteBackgroundForPrintEconomy(document, + style); + if (force_background_to_white) { + text_style.fill_color = + TextColorForWhiteBackground(text_style.fill_color); + text_style.stroke_color = + TextColorForWhiteBackground(text_style.stroke_color); + text_style.emphasis_mark_color = + TextColorForWhiteBackground(text_style.emphasis_mark_color); } - - if (style.StrokePaint().HasColor()) { - const Color color = style.VisitedDependentColor(GetCSSPropertyStroke()); - const float alpha = style.StrokeOpacity(); - text_style.stroke_color = ScaleAlpha(color.Rgb(), alpha); - } else { - text_style.stroke_color = Color::kTransparent; - } - - text_style.emphasis_mark_color = - style.VisitedDependentColor(GetCSSPropertyWebkitTextEmphasisColor()); - text_style.shadow = style.TextShadow(); - - AdjustTextStyleForPrint(document, style, text_style); } return text_style;
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.h b/third_party/blink/renderer/core/paint/text_painter_base.h index 4cdf405..bba7e4bb 100644 --- a/third_party/blink/renderer/core/paint/text_painter_base.h +++ b/third_party/blink/renderer/core/paint/text_painter_base.h
@@ -25,7 +25,6 @@ class GraphicsContext; class GraphicsContextStateSaver; class Node; -class SVGLengthContext; class TextDecorationOffsetBase; struct PaintInfo; @@ -72,10 +71,6 @@ static TextPaintStyle TextPaintingStyle(const Document&, const ComputedStyle&, const PaintInfo&); - static TextPaintStyle SvgTextPaintingStyle(const Document&, - const SVGLengthContext&, - const ComputedStyle&, - const PaintInfo&); static TextPaintStyle SelectionPaintingStyle( const Document&, const ComputedStyle&, @@ -89,10 +84,6 @@ static AffineTransform Rotation(const PhysicalRect& box_rect, WritingMode); protected: - static void AdjustTextStyleForClip(TextPaintStyle&); - static void AdjustTextStyleForPrint(const Document&, - const ComputedStyle&, - TextPaintStyle&); void UpdateGraphicsContext(const TextPaintStyle& style, GraphicsContextStateSaver& saver) { UpdateGraphicsContext(graphics_context_, style, horizontal_, saver);
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index d682a10..cccc323 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -43,6 +43,8 @@ #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/html/html_body_element.h" +#include "third_party/blink/renderer/core/html/html_html_element.h" #include "third_party/blink/renderer/core/html/html_progress_element.h" #include "third_party/blink/renderer/core/layout/layout_theme.h" #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h" @@ -2542,6 +2544,27 @@ return static_cast<EPaintOrderType>(pt); } +bool ComputedStyle::ShouldApplyAnyContainment(const Element& element) const { + DCHECK(IsA<HTMLBodyElement>(element) || IsA<HTMLHtmlElement>(element)) + << "Since elements can override the computed display for which box type " + "to create, this method is not generally correct. Use " + "LayoutObject::ShouldApplyAnyContainment if possible."; + if (ContainsStyle()) + return true; + if (!element.LayoutObjectIsNeeded(*this)) + return false; + if (Display() == EDisplay::kInline) + return false; + if ((ContainsInlineSize() || ContainsBlockSize()) && + (!IsDisplayTableType() || Display() == EDisplay::kTableCaption)) { + return true; + } + return (ContainsLayout() || ContainsPaint()) && + (!IsDisplayTableType() || IsDisplayTableBox() || + Display() == EDisplay::kTableCell || + Display() == EDisplay::kTableCaption); +} + STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kAuto, EOverscrollBehavior::kAuto); STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kContain,
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index d9e8564a..4365e066 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2068,6 +2068,7 @@ bool ContainsBlockSize() const { return (Contain() & kContainsBlockSize) || IsBlockSizeContainer(); } + CORE_EXPORT bool ShouldApplyAnyContainment(const Element& element) const; // Display utility functions. bool IsDisplayReplacedType() const {
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc index b6503ce..f8a4ceb 100644 --- a/third_party/blink/renderer/core/style/computed_style_test.cc +++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -22,7 +22,10 @@ #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/node_computed_style.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/html/html_body_element.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/style/clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_value.h" @@ -1214,6 +1217,81 @@ TEST_STYLE_VALUE_NO_DIFF(BaselineShift); } +TEST_F(ComputedStyleTest, ShouldApplyAnyContainment) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr); + Document& document = dummy_page_holder->GetDocument(); + + auto* html = document.documentElement(); + auto* body = document.body(); + ASSERT_TRUE(html); + ASSERT_TRUE(body); + + auto display_types = {CSSValueID::kInline, + CSSValueID::kBlock, + CSSValueID::kListItem, + CSSValueID::kInlineBlock, + CSSValueID::kTable, + CSSValueID::kInlineTable, + CSSValueID::kTableRowGroup, + CSSValueID::kTableHeaderGroup, + CSSValueID::kTableFooterGroup, + CSSValueID::kTableRow, + CSSValueID::kTableColumnGroup, + CSSValueID::kTableColumn, + CSSValueID::kTableCell, + CSSValueID::kTableCaption, + CSSValueID::kWebkitBox, + CSSValueID::kWebkitInlineBox, + CSSValueID::kFlex, + CSSValueID::kInlineFlex, + CSSValueID::kGrid, + CSSValueID::kInlineGrid, + CSSValueID::kContents, + CSSValueID::kFlowRoot, + CSSValueID::kNone, + CSSValueID::kMath}; + + for (auto contain : + {CSSValueID::kNone, CSSValueID::kLayout, CSSValueID::kPaint, + CSSValueID::kSize, CSSValueID::kStyle}) { + html->SetInlineStyleProperty(CSSPropertyID::kContain, + getValueName(contain)); + body->SetInlineStyleProperty(CSSPropertyID::kContain, + getValueName(contain)); + for (auto html_display : display_types) { + html->SetInlineStyleProperty(CSSPropertyID::kDisplay, html_display); + for (auto body_display : display_types) { + body->SetInlineStyleProperty(CSSPropertyID::kDisplay, body_display); + document.View()->UpdateAllLifecyclePhasesForTest(); + + if (!html->GetLayoutObject()) { + EXPECT_TRUE(!html->GetComputedStyle()); + continue; + } + EXPECT_EQ(html->GetLayoutObject()->ShouldApplyAnyContainment(), + html->GetLayoutObject()->StyleRef().ShouldApplyAnyContainment( + *html)) + << "html contain:" << getValueName(contain) + << " display:" << getValueName(html_display); + if (!body->GetLayoutObject()) { + if (const auto* body_style = body->GetComputedStyle()) { + EXPECT_EQ(body_style->Display(), EDisplay::kContents); + EXPECT_EQ(body_style->ShouldApplyAnyContainment(*body), + contain == CSSValueID::kStyle); + } + continue; + } + EXPECT_EQ(body->GetLayoutObject()->ShouldApplyAnyContainment(), + body->GetLayoutObject()->StyleRef().ShouldApplyAnyContainment( + *body)) + << "body contain:" << getValueName(contain) + << " display:" << getValueName(body_display); + } + } + } +} + #if DCHECK_IS_ON() TEST_F(ComputedStyleTest, DebugDiffFields) {
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc index 8a6be8db..eecc49f1 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h" +#include <utility> + #include "base/threading/thread_checker.h" #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h" #include "third_party/blink/public/common/features.h" @@ -11,7 +13,9 @@ #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/loader/content_security_notifier.mojom-blink.h" #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h" +#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/public/platform/web_content_security_policy_struct.h" #include "third_party/blink/public/platform/web_worker_fetch_context.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" #include "third_party/blink/renderer/core/dom/events/event_queue.h" @@ -38,6 +42,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h" +#include "third_party/blink/renderer/platform/network/http_parsers.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -448,6 +453,16 @@ auto* csp = MakeGarbageCollected<ContentSecurityPolicy>(); csp->SetSupportsWasmEval(SchemeRegistry::SchemeSupportsWasmEvalCSP( GetSecurityOrigin()->Protocol())); + + // Check if the embedder wants to add any default policies, and add them. + WebVector<WebContentSecurityPolicyHeader> embedder_default_csp; + Platform::Current()->AppendContentSecurityPolicy(WebURL(Url()), + &embedder_default_csp); + for (const auto& header : embedder_default_csp) { + csp->AddPolicies(ParseContentSecurityPolicies( + header.header_value, header.type, header.source, Url())); + } + SetContentSecurityPolicy(csp); } GetContentSecurityPolicy()->AddPolicies(std::move(policies));
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index b2d1e4a..117bde81 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -105,6 +105,7 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/core/svg/svg_element.h" +#include "third_party/blink/renderer/core/svg/svg_title_element.h" #include "third_party/blink/renderer/modules/accessibility/ax_image_map_link.h" #include "third_party/blink/renderer/modules/accessibility/ax_inline_text_box.h" #include "third_party/blink/renderer/modules/accessibility/ax_layout_object.h" @@ -267,6 +268,32 @@ return ax::mojom::blink::TextDecorationStyle::kNone; } +String GetTitle(blink::Element* element) { + if (!element) + return String(); + + if (blink::SVGElement* svg_element = + blink::DynamicTo<blink::SVGElement>(element)) { + // Don't use title() in SVG, as it calls innerText() which updates layout. + // Unfortunately, this must duplicate some logic from SVGElement::title(). + if (svg_element->InUseShadowTree()) { + String title = GetTitle(svg_element->OwnerShadowHost()); + if (!title.IsEmpty()) + return title; + } + // If we aren't an instance in a <use> or the <use> title was not found, + // then find the first <title> child of this element. If a title child was + // found, return the text contents. + if (auto* title_element = + blink::Traversal<blink::SVGTitleElement>::FirstChild(*element)) { + return title_element->GetInnerTextWithoutUpdate(); + } + return String(); + } + + return element->title(); +} + } // namespace namespace blink { @@ -831,24 +858,18 @@ if (IsA<HTMLImageElement>(GetNode())) return ax::mojom::blink::Role::kImage; - // <a href> or <svg:a xlink:href> - if (GetNode()->IsLink()) { - // |HTMLAnchorElement| sets isLink only when it has kHrefAttr. - return ax::mojom::blink::Role::kLink; - } - - if (IsA<HTMLPortalElement>(*GetNode())) { - return ax::mojom::blink::Role::kPortal; - } - - if (IsA<HTMLAnchorElement>(*GetNode())) { - // We assume that an anchor element is LinkRole if it has event listeners - // even though it doesn't have kHrefAttr. - if (IsClickable()) + // <a> or <svg:a>. + if (IsA<HTMLAnchorElement>(GetNode()) || IsA<SVGAElement>(GetNode())) { + // Assume that an anchor element is a Role::kLink if it has an href or a + // click event listener. + if (GetNode()->IsLink() || IsClickable()) return ax::mojom::blink::Role::kLink; - return ax::mojom::blink::Role::kAnchor; + return ax::mojom::blink::Role::kGenericContainer; } + if (IsA<HTMLPortalElement>(*GetNode())) + return ax::mojom::blink::Role::kPortal; + if (IsA<HTMLButtonElement>(*GetNode())) return ButtonRoleType(); @@ -5264,15 +5285,9 @@ String AXNodeObject::Title(ax::mojom::blink::NameFrom name_from) const { if (name_from == ax::mojom::blink::NameFrom::kTitle) - return String(); + return String(); // Already exposed the title in the name field. - if (const auto* element = GetElement()) { - String title = element->title(); - if (!title.IsEmpty()) - return title; - } - - return String(); + return GetTitle(GetElement()); } String AXNodeObject::PlaceholderFromNativeAttribute() const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index a8e4445b..fd893bc 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -2027,20 +2027,6 @@ bool is_ignored = ComputeAccessibilityIsIgnored(); bool is_ignored_but_included_in_tree = is_ignored && ComputeAccessibilityIsIgnoredButIncludedInTree(); -#if DCHECK_IS_ON() - // Ensure that display-locked text is pruned from the tree. This means that - // they will be missed in the virtual buffer; therefore, it may be a rule - // subject to change. Note that changing the rule would potentially cause a - // lot of display-locked whitespace to be exposed. - if (is_ignored && RoleValue() == ax::mojom::blink::Role::kStaticText && - GetNode() && - DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) { - DCHECK(!cached_is_ignored_but_included_in_tree_) - << "Display locked text should not be included in the tree (subject to " - "future rule change): " - << ToString(true, true); - } -#endif bool included_in_tree_changed = false; // If the child's "included in tree" state changes, we will be notifying the @@ -5202,7 +5188,6 @@ switch (RoleValue()) { // ----- NameFrom: contents ------------------------- // Get their own name from contents, or contribute to ancestors - case ax::mojom::blink::Role::kAnchor: case ax::mojom::blink::Role::kButton: case ax::mojom::blink::Role::kCell: case ax::mojom::blink::Role::kCheckBox:
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index fe301c0..616a4b67 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -1326,6 +1326,7 @@ Remove(object->AXObjectID()); } +// This is safe to call even if there isn't a current mapping. void AXObjectCacheImpl::Remove(AXID ax_id) { if (!ax_id) return; @@ -1354,48 +1355,77 @@ DCHECK_GE(objects_.size(), ids_in_use_.size()); } +// This is safe to call even if there isn't a current mapping. void AXObjectCacheImpl::Remove(AccessibleNode* accessible_node) { if (!accessible_node) return; - AXID ax_id = accessible_node_mapping_.at(accessible_node); - accessible_node_mapping_.erase(accessible_node); + auto iter = accessible_node_mapping_.find(accessible_node); + if (iter == accessible_node_mapping_.end()) + return; + + AXID ax_id = iter->value; + accessible_node_mapping_.erase(iter); Remove(ax_id); } +// This is safe to call even if there isn't a current mapping. bool AXObjectCacheImpl::Remove(LayoutObject* layout_object) { if (!layout_object) return false; - AXID ax_id = layout_object_mapping_.at(layout_object); - if (!ax_id) + auto iter = layout_object_mapping_.find(layout_object); + if (iter == layout_object_mapping_.end()) return false; - layout_object_mapping_.erase(layout_object); + AXID ax_id = iter->value; + DCHECK(ax_id); + + layout_object_mapping_.erase(iter); Remove(ax_id); return true; } +// This is safe to call even if there isn't a current mapping. void AXObjectCacheImpl::Remove(Node* node) { if (!node) return; - // This is all safe even if we didn't have a mapping. - AXID ax_id = node_object_mapping_.at(node); - node_object_mapping_.erase(node); + LayoutObject* layout_object = node->GetLayoutObject(); - if (!Remove(node->GetLayoutObject())) + // A layout object will be used whenever it is available and relevant. It's + // the preferred backing object, rather than the DOM node. + if (Remove(node->GetLayoutObject())) { + DCHECK_EQ(node_object_mapping_.find(node), node_object_mapping_.end()) + << "AXObject cannot be backed by both a layout object and node."; + return; + } + + auto iter = node_object_mapping_.find(node); + if (iter != node_object_mapping_.end()) { + DCHECK(!layout_object || layout_object_mapping_.find(layout_object) == + layout_object_mapping_.end()) + << "AXObject cannot be backed by both a layout object and node."; + AXID ax_id = iter->value; + DCHECK(ax_id); + node_object_mapping_.erase(iter); Remove(ax_id); + } } +// This is safe to call even if there isn't a current mapping. void AXObjectCacheImpl::Remove(AbstractInlineTextBox* inline_text_box) { if (!inline_text_box) return; - AXID ax_id = inline_text_box_object_mapping_.at(inline_text_box); - inline_text_box_object_mapping_.erase(inline_text_box); + auto iter = inline_text_box_object_mapping_.find(inline_text_box); + if (iter == inline_text_box_object_mapping_.end()) + return; + + AXID ax_id = iter->value; + inline_text_box_object_mapping_.erase(iter); Remove(ax_id); }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc index d6afb38..1d17a93 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc
@@ -209,6 +209,7 @@ auto* arg = MakeGarbageCollected<V8UnionBooleanOrScrollIntoViewOptions>(options); checked_item_->scrollIntoView(arg); + checked_item_->focus(); } void MediaControlPlaybackSpeedListElement::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl index 0ec1f52..165cf05 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_data_init.idl
@@ -5,6 +5,6 @@ // https://github.com/WICG/web-codecs dictionary AudioDataInit { - required long long timestamp; // microseconds + required [EnforceRange] long long timestamp; // microseconds required AudioBuffer buffer; };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl b/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl index 9948360..fc3527f 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder_config.idl
@@ -12,10 +12,10 @@ required DOMString codec; // Rate of samples per second. 44100, 48000, etc. - required unsigned long sampleRate; + required [EnforceRange] unsigned long sampleRate; // 1, 2, etc. - required unsigned long numberOfChannels; + required [EnforceRange] unsigned long numberOfChannels; // Optional byte data required to initialize audio decoders such as Vorbis // codebooks.
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl b/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl index ab29c94..8d8f0499 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder_config.idl
@@ -11,10 +11,10 @@ required DOMString codec; // Rate of samples per second. 44100, 48000, etc. - required unsigned long sampleRate; + required [EnforceRange] unsigned long sampleRate; // 1, 2, etc. - required unsigned short numberOfChannels; + required [EnforceRange] unsigned short numberOfChannels; - unsigned long long bitrate; + [EnforceRange] unsigned long long bitrate; };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl index 41ff977..b64b6afc 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl
@@ -6,6 +6,6 @@ dictionary EncodedAudioChunkInit { required EncodedAudioChunkType type; - required long long timestamp; // microseconds + required [EnforceRange] long long timestamp; // microseconds required BufferSource data; };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl index a499ecf8..9c86828 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl
@@ -6,7 +6,7 @@ dictionary EncodedVideoChunkInit { required EncodedVideoChunkType type; - required long long timestamp; // microseconds - unsigned long long duration; // microseconds + required [EnforceRange] long long timestamp; // microseconds + [EnforceRange] unsigned long long duration; // microseconds required BufferSource data; };
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl index da51cd23..4ae2695 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl +++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl
@@ -6,5 +6,5 @@ dictionary EncodedVideoChunkMetadata { VideoDecoderConfig decoderConfig; - unsigned long temporalLayerId; + [EnforceRange] unsigned long temporalLayerId; };
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl b/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl index a38fdff..8cc91b4 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl +++ b/third_party/blink/renderer/modules/webcodecs/image_decode_options.idl
@@ -6,7 +6,7 @@ dictionary ImageDecodeOptions { // The index of the frame to decode. - unsigned long frameIndex = 0; + [EnforceRange] unsigned long frameIndex = 0; // When |completeFramesOnly| is set to false, partial progressive frames will // be returned. When in this mode, decode() calls will resolve only once per
diff --git a/third_party/blink/renderer/modules/webcodecs/image_track_list.idl b/third_party/blink/renderer/modules/webcodecs/image_track_list.idl index d380cc3..e96fc2c 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_track_list.idl +++ b/third_party/blink/renderer/modules/webcodecs/image_track_list.idl
@@ -8,7 +8,7 @@ Exposed=(Window,DedicatedWorker), RuntimeEnabled=WebCodecs ] interface ImageTrackList { - getter ImageTrack(unsigned long index); + getter ImageTrack([EnforceRange] unsigned long index); readonly attribute unsigned long length; // Index of the currently selected track or -1 if no track is selected.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl b/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl index 80d801c..211ab00 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
@@ -11,7 +11,7 @@ HardwarePreference hardwareAcceleration = "allow"; AlphaOption alpha = "discard"; - unsigned long long bitrate; + [EnforceRange] unsigned long long bitrate; double framerate;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl b/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl index f9d8a2c..4903ddc3 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_frame_init.idl
@@ -6,7 +6,7 @@ enum AlphaOption { "discard", "keep" }; dictionary VideoFrameInit { - long long timestamp; // microseconds - unsigned long long duration; // microseconds + [EnforceRange] long long timestamp; // microseconds + [EnforceRange] unsigned long long duration; // microseconds AlphaOption alpha = "keep"; };
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl b/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl index 68bb198..b7c9aec 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl
@@ -7,8 +7,8 @@ dictionary VideoFramePlaneInit { required VideoPixelFormat format; - required long long timestamp; // microseconds - unsigned long long duration; // microseconds + required [EnforceRange] long long timestamp; // microseconds + [EnforceRange] unsigned long long duration; // microseconds required [EnforceRange] unsigned long codedWidth; required [EnforceRange] unsigned long codedHeight;
diff --git a/third_party/blink/renderer/platform/bindings/idl_member_installer.cc b/third_party/blink/renderer/platform/bindings/idl_member_installer.cc index 90a743b..1f6f792d 100644 --- a/third_party/blink/renderer/platform/bindings/idl_member_installer.cc +++ b/third_party/blink/renderer/platform/bindings/idl_member_installer.cc
@@ -137,8 +137,7 @@ v8::Local<v8::Signature> signature, v8::Local<v8::String> name, const Config& config, - const v8::CFunction* v8_cfunction_table_data = nullptr, - uint32_t v8_cfunction_table_size = 0) { + const v8::CFunction* v8_c_function = nullptr) { v8::FunctionCallback callback = GetConfigCallback<kind>(config); if (!callback) return v8::Local<v8::FunctionTemplate>(); @@ -153,10 +152,9 @@ (v8_cached_accessor == V8PrivateProperty::CachedAccessor::kWindowDocument && !world.IsMainWorld())) { - function_template = v8::FunctionTemplate::NewWithCFunctionOverloads( + function_template = v8::FunctionTemplate::New( isolate, callback, v8::Local<v8::Value>(), signature, length, - v8::ConstructorBehavior::kThrow, v8_side_effect, - {v8_cfunction_table_data, v8_cfunction_table_size}); + v8::ConstructorBehavior::kThrow, v8_side_effect, v8_c_function); } else { function_template = v8::FunctionTemplate::NewWithCache( isolate, callback, @@ -182,14 +180,12 @@ v8::Local<v8::Signature> signature, v8::Local<v8::String> name, const Config& config, - const v8::CFunction* v8_cfunction_table_data = nullptr, - uint32_t v8_cfunction_table_size = 0) { + const v8::CFunction* v8_c_function = nullptr) { if (!GetConfigCallback<kind>(config)) return v8::Local<v8::Function>(); return CreateFunctionTemplate<kind>(isolate, world, signature, name, config, - v8_cfunction_table_data, - v8_cfunction_table_size) + v8_c_function) ->GetFunction(context) .ToLocalChecked(); } @@ -302,8 +298,7 @@ v8::Local<v8::Template> interface_template, v8::Local<v8::Signature> signature, const IDLMemberInstaller::OperationConfig& config, - const v8::CFunction* v8_cfunction_table_data = nullptr, - uint32_t v8_cfunction_table_size = 0) { + const v8::CFunction* v8_c_function = nullptr) { if (!DoesWorldMatch(config, world)) return; @@ -318,8 +313,7 @@ v8::Local<v8::String> name = V8AtomicString(isolate, config.name); v8::Local<v8::FunctionTemplate> func = CreateFunctionTemplate<FunctionKind::kOperation>( - isolate, world, signature, name, config, v8_cfunction_table_data, - v8_cfunction_table_size); + isolate, world, signature, name, config, v8_c_function); v8::Local<v8::Template> target_template; switch (location) { @@ -348,8 +342,7 @@ v8::Local<v8::Object> interface_object, v8::Local<v8::Signature> signature, const IDLMemberInstaller::OperationConfig& config, - const v8::CFunction* v8_cfunction_table_data = nullptr, - uint32_t v8_cfunction_table_size = 0) { + const v8::CFunction* v8_c_function = nullptr) { if (!DoesWorldMatch(config, world)) return; @@ -363,8 +356,7 @@ v8::Local<v8::String> name = V8AtomicString(isolate, config.name); v8::Local<v8::Function> func = CreateFunction<FunctionKind::kOperation>( - isolate, context, world, signature, name, config, v8_cfunction_table_data, - v8_cfunction_table_size); + isolate, context, world, signature, name, config, v8_c_function); v8::Local<v8::Object> target_object; switch (location) { @@ -519,8 +511,7 @@ for (const auto& config : configs) { InstallOperation(isolate, world, instance_template, prototype_template, interface_template, signature, config.operation_config, - config.v8_cfunction_table_data, - config.v8_cfunction_table_size); + &config.v8_c_function); } } @@ -537,8 +528,7 @@ for (const auto& config : configs) { InstallOperation(isolate, context, world, instance_object, prototype_object, interface_object, signature, config.operation_config, - config.v8_cfunction_table_data, - config.v8_cfunction_table_size); + &config.v8_c_function); } }
diff --git a/third_party/blink/renderer/platform/bindings/idl_member_installer.h b/third_party/blink/renderer/platform/bindings/idl_member_installer.h index 2d09b2f3..434d246 100644 --- a/third_party/blink/renderer/platform/bindings/idl_member_installer.h +++ b/third_party/blink/renderer/platform/bindings/idl_member_installer.h
@@ -138,8 +138,7 @@ struct NoAllocDirectCallOperationConfig { OperationConfig operation_config; - const v8::CFunction* v8_cfunction_table_data; - uint32_t v8_cfunction_table_size; + v8::CFunction v8_c_function; }; static void InstallOperations( v8::Isolate* isolate,
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index 1a4f05d..de01599 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -351,12 +351,21 @@ const PaintArtifact& previous_artifact, const PaintChunk& repainted, const PaintArtifact& repainted_artifact) { - if (repainted.is_moved_from_cached_subsequence) - return false; - if (!repainted.Matches(previous)) return true; + if (repainted.is_moved_from_cached_subsequence) { + DCHECK_EQ(previous.bounds, repainted.bounds); + DCHECK_EQ(previous.known_to_be_opaque, repainted.known_to_be_opaque); + DCHECK_EQ(previous.text_known_to_be_on_opaque_background, + repainted.text_known_to_be_on_opaque_background); + // Not checking ForeignLayer() here because the old ForeignDisplayItem + // was set to 0 when we moved the cached subsequence. This is also the + // reason why we check is_moved_from_cached_subsequence before checking + // ForeignLayer(). + return false; + } + // Bounds are used in overlap testing. // TODO(pdr): If the bounds shrink, that does affect overlap testing but we // could return false to continue using less-than-optimal overlap testing in
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc index a1fd8d2..98c186d 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -637,6 +637,17 @@ : Font::DrawType::kGlyphsOnly); } +void GraphicsContext::DrawText(const Font& font, + const NGTextFragmentPaintInfo& text_info, + const FloatPoint& point, + const PaintFlags& flags, + DOMNodeId node_id) { + font.DrawText(canvas_, text_info, point, device_scale_factor_, node_id, + DarkModeFlags(this, flags, DarkModeFilter::ElementRole::kText), + printing_ ? Font::DrawType::kGlyphsAndClusters + : Font::DrawType::kGlyphsOnly); +} + template <typename DrawTextFunc> void GraphicsContext::DrawTextPasses(const DrawTextFunc& draw_text) { TextDrawingModeFlags mode_flags = TextDrawingMode();
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h index afeee01..8d71d83 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.h +++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -311,6 +311,14 @@ const PaintFlags&, DOMNodeId); + // TODO(layout-dev): This method is only used by NGTextPainter, see if the + // four parameter overload can be removed or if it can wrap this method. + void DrawText(const Font&, + const NGTextFragmentPaintInfo&, + const FloatPoint&, + const PaintFlags&, + DOMNodeId); + void DrawEmphasisMarks(const Font&, const TextRunPaintInfo&, const AtomicString& mark,
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc index 33aece5..65dd419 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -180,6 +180,10 @@ } } + // To mirror what RTCVideoDecoderStreamAdapter does a little more closely, + // record an init failure here. Otherwise, we only ever record successes. + base::UmaHistogramBoolean("Media.RTCVideoDecoderInitDecodeSuccess", false); + return nullptr; } @@ -253,7 +257,8 @@ current_resolution_ = static_cast<int32_t>(codec_settings->width) * codec_settings->height; - UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", !has_error_); + base::UmaHistogramBoolean("Media.RTCVideoDecoderInitDecodeSuccess", + !has_error_); if (!has_error_) { UMA_HISTOGRAM_ENUMERATION( "Media.RTCVideoDecoderProfile",
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc index bf466d9..e7bae62 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -8,6 +8,7 @@ #include <functional> #include <utility> +#include "base/atomic_ref_count.h" #include "base/callback_helpers.h" #include "base/containers/circular_deque.h" #include "base/feature_list.h" @@ -74,6 +75,17 @@ // never completed, or (c) we're hopelessly behind. constexpr int32_t kAbsoluteMaxPendingBuffers = 32; +// Name we'll report for hardware decoders. +constexpr const char* kExternalDecoderName = "ExternalDecoder"; + +// Number of RTCVideoDecoder instances right now that have started decoding. +std::atomic_int* GetDecoderCounter() { + static base::NoDestructor<std::atomic_int> s_counter(0); + // Note that this will init only in the first call in the ctor, so it's still + // single threaded. + return s_counter.get(); +} + void RecordInitializationLatency(base::TimeDelta latency) { base::UmaHistogramTimes("Media.RTCVideoDecoderInitializationLatencyMs", latency); @@ -81,6 +93,9 @@ } // namespace +// static +constexpr gfx::Size RTCVideoDecoderStreamAdapter::kMinResolution; + // DemuxerStream implementation that forwards DecoderBuffer from some other // source (i.e., VideoDecoder::Decode). class RTCVideoDecoderStreamAdapter::InternalDemuxerStream @@ -245,7 +260,10 @@ config_(config), max_pending_buffer_count_(kAbsoluteMaxPendingBuffers) { DVLOG(1) << __func__; - decoder_info_.implementation_name = "unknown"; + // Default to hw-accelerated decoder, in case something checks before decoding + // a frame. It's unclear what we should report in the long run, but for now, + // it's better to report hardware since that's all we support anyway. + decoder_info_.implementation_name = kExternalDecoderName; decoder_info_.is_hardware_accelerated = false; DETACH_FROM_SEQUENCE(decoding_sequence_checker_); weak_this_ = weak_this_factory_.GetWeakPtr(); @@ -254,6 +272,9 @@ RTCVideoDecoderStreamAdapter::~RTCVideoDecoderStreamAdapter() { DVLOG(1) << __func__; DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); + + if (have_started_decoding_) + --(*GetDecoderCounter()); } void RTCVideoDecoderStreamAdapter::InitializeSync( @@ -289,6 +310,8 @@ base::AutoLock auto_lock(lock_); init_decode_complete_ = true; + current_resolution_ = + gfx::Size(codec_settings->width, codec_settings->height); AttemptLogInitializationState_Locked(); return has_error_ ? WEBRTC_VIDEO_CODEC_UNINITIALIZED : WEBRTC_VIDEO_CODEC_OK; } @@ -308,7 +331,8 @@ logged_init_status_ = true; - UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", !has_error_); + base::UmaHistogramBoolean("Media.RTCVideoDecoderInitDecodeSuccess", + !has_error_); if (!has_error_) { UMA_HISTOGRAM_ENUMERATION( "Media.RTCVideoDecoderProfile", @@ -324,6 +348,36 @@ DVLOG(2) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_); + // If this is the first decode, then increment the count of working decoders. + if (!have_started_decoding_) { + have_started_decoding_ = true; + ++(*GetDecoderCounter()); + } + +#if defined(OS_ANDROID) && !BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS) + const bool has_software_fallback = + video_codec_type_ != webrtc::kVideoCodecH264; +#else + const bool has_software_fallback = true; +#endif + + // Don't allow hardware decode for small videos if there are too many + // decoder instances. This includes the case where our resolution drops while + // too many decoders exist. When DecoderStream supports software decoders, + // this should be moved to DecoderSelector. + { + base::AutoLock auto_lock(lock_); + if (has_software_fallback && + current_resolution_.GetArea() < kMinResolution.GetArea() && + GetDecoderCounter()->load() > kMaxDecoderInstances) { + // Decrement the count and clear the flag, so that other decoders don't + // fall back also. + have_started_decoding_ = false; + --(*GetDecoderCounter()); + return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; + } + } + // Fall back to software decoding if there's no support for VP9 spatial // layers. See https://crbug.com/webrtc/9304. // TODO(chromium:1187565): Update RTCVideoDecoderFactory::QueryCodecSupport() @@ -413,12 +467,6 @@ // drop any other non-key frame. key_frame_required_ = true; -#if defined(OS_ANDROID) && !BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS) - const bool has_software_fallback = - video_codec_type_ != webrtc::kVideoCodecH264; -#else - const bool has_software_fallback = true; -#endif // If we hit the absolute limit, then give up. if (has_software_fallback && pending_buffer_count_ >= kAbsoluteMaxPendingBuffers) { @@ -645,6 +693,10 @@ start_time_.reset(); } + // Update `current_resolution_`, in case it's changed. This lets us fall back + // to software, or avoid doing so, if we're over the decoder limit. + current_resolution_ = gfx::Size(rtc_frame.width(), rtc_frame.height()); + // Try to read the next output, if any, regardless if this succeeded. AttemptRead_Locked(); @@ -774,7 +826,7 @@ decoder_info_.is_hardware_accelerated = decoder->IsPlatformDecoder(); decoder_info_.implementation_name = decoder->IsPlatformDecoder() - ? "ExternalDecoder" + ? kExternalDecoderName : media::GetDecoderName(decoder->GetDecoderType()) + " (DecoderStream)"; }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h index 6f1b575..22a4de1 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.h
@@ -62,6 +62,20 @@ class PLATFORM_EXPORT RTCVideoDecoderStreamAdapter : public webrtc::VideoDecoder { public: + // Minimum resolution that we'll consider "not low resolution" for the purpose + // of falling back to software. +#if defined(OS_CHROMEOS) + // Effectively opt-out CrOS, since it may cause tests to fail (b/179724180). + static constexpr gfx::Size kMinResolution{2, 2}; +#else + static constexpr gfx::Size kMinResolution{320, 240}; +#endif + + // Maximum number of decoder instances we'll allow before fallback to software + // if the resolution is too low. We'll allow more than this for high + // resolution streams, but they'll fall back if they adapt below the limit. + static constexpr int32_t kMaxDecoderInstances = 8; + // Creates and initializes an RTCVideoDecoderStreamAdapter. Returns nullptr if // |format| cannot be supported. The gpu_factories may be null, in which case // only SW decoders will be used. @@ -161,6 +175,8 @@ // Decoding thread members. bool key_frame_required_ = true; webrtc::VideoCodecType video_codec_type_ = webrtc::kVideoCodecGeneric; + // Has anything been sent to Decode() yet? + bool have_started_decoding_ = false; // Shared members. mutable base::Lock lock_; @@ -184,6 +200,10 @@ // Time since construction. Cleared when we record that a frame has been // successfully decoded. absl::optional<base::TimeTicks> start_time_ GUARDED_BY(lock_); + // Resolution of most recently decoded frame, or the initial resolution if we + // haven't decoded anything yet. Since this is updated asynchronously, it's + // only an approximation of "most recently". + gfx::Size current_resolution_ GUARDED_BY(lock_); // Do we have an outstanding `DecoderStream::Read()`? // Media thread only.
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py index 918c7a7..7a6020a 100644 --- a/third_party/blink/tools/blinkpy/w3c/test_importer.py +++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -186,7 +186,7 @@ _log.info('Only manifest was updated; skipping the import.') return 0 - with self._expectations_updater.prepare_smoke_tests(): + with self._expectations_updater.prepare_smoke_tests(self.chromium_git): self._commit_changes(commit_message) _log.info('Changes imported and committed.')
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py index 4fe8e77..415d2d9 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -781,7 +781,7 @@ return line_dict @contextlib.contextmanager - def prepare_smoke_tests(self): + def prepare_smoke_tests(self, chromium_git): """List test cases that should be run by the smoke test builder Add new and modified test cases to WPT_SMOKE_TESTS_FILE, @@ -819,6 +819,7 @@ finally: _log.info('Restore file WPTSmokeTestCases.') shutil.copyfile(self._saved_test_cases_file, WPT_SMOKE_TESTS_FILE) + chromium_git.commit_locally_with_message('Restore WPTSmokeTestCases') def cleanup_test_expectations_files(self): """Removes deleted tests from expectations files.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 79432b5..2ecac5e 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -219,6 +219,10 @@ crbug.com/1126305 wpt_internal/prerender/* [ Skip ] crbug.com/1126305 virtual/prerender/wpt_internal/prerender/* [ Pass ] +## prerender test: speculationrules script do not set referrers. +crbug.com/1215932 virtual/prerender/wpt_internal/prerender/referrer-policy-origin.html [ Failure ] +crbug.com/1215932 virtual/prerender/wpt_internal/prerender/referrer.html [ Failure ] + ## prerender test: the File System Access API is not supported on Android ## crbug.com/1182032 [ Android ] virtual/prerender/wpt_internal/prerender/restriction-local-file-system-access.https.html [ Skip ] ## prerender test: Notification constructor is not supported on Android ## @@ -3786,6 +3790,8 @@ crbug.com/1045599 external/wpt/css/css-grid/grid-definition/grid-auto-repeat-dynamic-003.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/grid-definition/grid-repeat-max-width-001.html [ Failure ] crbug.com/1045599 external/wpt/css/css-grid/grid-items/aspect-ratio-004.html [ Failure ] +crbug.com/1045599 external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-002.tentative.html [ Failure ] +crbug.com/1045599 external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-003.tentative.html [ Failure ] crbug.com/1053825 external/wpt/css/css-grid/grid-model/grid-overflow-padding-001.html [ Failure ] crbug.com/1053825 external/wpt/css/css-grid/grid-model/grid-overflow-padding-002.html [ Failure ] crbug.com/1053825 external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html [ Failure ] @@ -3797,6 +3803,8 @@ crbug.com/935102 external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-002.html [ Failure ] crbug.com/935102 external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-003.html [ Failure ] crbug.com/1045599 fast/css-grid-layout/maximize-tracks-definite-indefinite-height.html [ Failure ] +crbug.com/1045599 external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-025.html [ Failure ] +crbug.com/1045599 external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-026.html [ Failure ] # Bad stretching of svgs without aspect-ratio. crbug.com/1114013 external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html [ Failure ] @@ -3901,6 +3909,8 @@ virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-dynamic-003.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/aspect-ratio-004.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-auto-margin-and-replaced-item-001.html [ Pass ] +virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-002.tentative.html [ Pass ] +virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-003.tentative.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-002.html [ Pass ] virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-003.html [ Pass ] @@ -6333,7 +6343,7 @@ # Sheriff 2021-03-08 crbug.com/1092462 [ Linux ] http/tests/media/media-source/mediasource-duration.html [ Pass Failure ] -crbug.com/1092462 [ Linux ] virtual/synchronous_html_parser/media/video-seek-past-end-paused.html [ Pass Failure ] +crbug.com/1092462 [ Linux ] media/video-seek-past-end-paused.html [ Pass Failure ] crbug.com/1185675 [ Mac ] virtual/gpu-rasterization/images/color-profile-object.html [ Pass Failure ] crbug.com/1185676 [ Mac ] http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-end-to-end.js [ Pass Failure ] @@ -6487,6 +6497,7 @@ # Sheriff 2021-04-14 crbug.com/1198828 [ Win ] virtual/scroll-unification/fast/events/mouse-events-on-node-deletion.html [ Pass Failure ] +crbug.com/1198828 [ Linux ] virtual/scroll-unification/fast/events/mouse-events-on-node-deletion.html [ Pass Failure ] # Sheriff 2021-04-15 crbug.com/1199380 virtual/scroll-unification-prefer_compositing_to_lcd_text/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Skip ] @@ -6913,34 +6924,6 @@ crbug.com/1048761 external/wpt/websockets/interfaces/WebSocket/events/018.html?wpt_flags=h2 [ Failure ] crbug.com/1048761 external/wpt/websockets/interfaces/WebSocket/send/006.html?wpt_flags=h2 [ Failure ] -# Fix to unblock wpt-importer -crbug.com/1209223 external/wpt/css/css-typed-om/idlharness.html [ Failure ] -crbug.com/1209223 external/wpt/html/dom/idlharness.https.html?exclude=(Document|Window|HTML.\*) [ Failure ] -crbug.com/1209223 [ Linux ] external/wpt/html/dom/idlharness.https.html?include=HTML.* [ Failure ] -crbug.com/1209223 [ Win ] external/wpt/html/dom/idlharness.https.html?include=HTML.* [ Failure ] -crbug.com/1209223 external/wpt/html/dom/idlharness.worker.html [ Failure ] -crbug.com/1209223 external/wpt/html/semantics/forms/form-submission-0/newline-normalization.html [ Failure ] -crbug.com/1209223 external/wpt/html/semantics/forms/the-textarea-element/wrapping-transformation.window.html [ Failure ] -crbug.com/1209223 external/wpt/payment-handler/idlharness.https.any.serviceworker.html [ Failure ] -crbug.com/1209223 external/wpt/payment-handler/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/1209223 external/wpt/payment-handler/idlharness.https.any.worker.html [ Failure ] -crbug.com/1209223 external/wpt/payment-request/idlharness.https.window.html [ Failure ] -crbug.com/1209223 external/wpt/private-click-measurement/idlharness.window.html [ Failure ] -crbug.com/1209223 external/wpt/url/url-setters-a-area.window.html [ Failure ] -crbug.com/1209223 external/wpt/url/url-setters.any.html [ Failure ] -crbug.com/1209223 external/wpt/url/url-setters.any.worker.html [ Failure ] -crbug.com/1209223 external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure ] -crbug.com/1209223 external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html [ Failure ] -crbug.com/1209223 external/wpt/webxr/idlharness.https.window.html [ Failure ] -crbug.com/1209223 external/wpt/xhr/formdata/constructor-formelement.html [ Failure ] -crbug.com/1209223 virtual/plz-dedicated-worker/external/wpt/xhr/formdata/constructor-formelement.html [ Failure ] -crbug.com/1209223 virtual/shared_array_buffer_on_desktop/external/wpt/xhr/formdata/constructor-formelement.html [ Failure ] -crbug.com/1209223 [ Mac10.15 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js [ Timeout ] -crbug.com/1209223 virtual/synchronous_html_parser/external/wpt/html/semantics/forms/form-submission-0/newline-normalization.html [ Failure ] -crbug.com/1167095 virtual/synchronous_html_parser/external/wpt/html/semantics/forms/the-textarea-element/wrapping-transformation.window.html [ Failure ] -crbug.com/1209223 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure ] -crbug.com/1209223 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html [ Failure ] - # Sheriff on 2021-05-26 crbug.com/1213322 [ Mac ] external/wpt/css/css-values/minmax-percentage-serialize.html [ Pass Failure ] crbug.com/1213322 [ Mac ] external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/window-named-properties.html [ Pass Failure ] @@ -6966,4 +6949,11 @@ # Sheriff 2021-06-03 crbug.com/1185121 fast/scroll-snap/animate-fling-to-snap-points-1.html [ Pass Failure ] +crbug.com/1176162 [ Linux ] http/tests/devtools/screen-orientation-override.js [ Pass Failure ] crbug.com/1215949 external/wpt/pointerevents/pointerevent_iframe-touch-action-none_touch.html [ Pass Timeout ] +crbug.com/1216139 virtual/bfcache/http/tests/devtools/bfcache/bfcache-elements-update.js [ Pass Failure ] + +# TODO(csmartalton): Tessellation improves these tests. Rebaseline after Skia roll. +skbug.com/10419 [ Fuchsia ] tables/mozilla/bugs/bug2479-3.html [ Pass Failure ] +skbug.com/10419 [ Fuchsia ] tables/mozilla/bugs/bug7342.html [ Pass Failure ] +skbug.com/10419 [ Fuchsia ] tables/mozilla/bugs/bug59354.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 29eb132..ebe1ab3 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -349,7 +349,9 @@ "prefix": "layout-ng-grid", "bases": ["fast/css-grid-layout", "external/wpt/css/css-sizing/aspect-ratio", - "external/wpt/css/css-grid"], + "external/wpt/css/css-grid", + "external/wpt/css/css-contain", + "external/wpt/css/css-sizing/contain-intrinsic-size"], "args": ["--enable-blink-features=LayoutNGGrid"] }, { @@ -1044,14 +1046,15 @@ }, { "prefix": "force-renderer-accessibility", - "bases": ["accessibility/slot-poison.html", - "accessibility/details-summary-crash.html", + "bases": ["accessibility/details-summary-crash.html", + "accessibility/slot-poison.html", "accessibility/virtual-node-child-removal.html", "accessibility/virtual-node-parent-removal.html", "accessibility/virtual-node-build-parent.html", "accessibility/virtual-node-build-parent-multiple.html", "accessibility/virtual-node-removed-from-document.html", - "accessibility/virtual-node-repair-document.html"], + "accessibility/virtual-node-repair-document.html", + "external/wpt/accessibility/crashtests/content-visibility-generated-content-removal.html"], "args": ["--force-renderer-accessibility"] }, {
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index f31f7d2..530c91a 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -185,6 +185,10 @@ crbug.com/1192234 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,encoding,cmds,setBindGroup:u32array_start_and_length:* [ Failure ] +# crbug.com/1215024 +wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createComputePipeline:enrty_point_name_must_match:stageEntryPoint="main%5Cu0000";* [ Failure ] +wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createComputePipeline:enrty_point_name_must_match:stageEntryPoint="main%5Cu0000a";* [ Failure ] + # Crash with validation layer. wpt_internal/webgpu/cts.html?q=webgpu:api,operation,render_pipeline,primitive_topology:* [ Failure Crash ]
diff --git a/third_party/blink/web_tests/accessibility/clickable-expected.txt b/third_party/blink/web_tests/accessibility/clickable-expected.txt index d91a2ab8..c79e8d1 100644 --- a/third_party/blink/web_tests/accessibility/clickable-expected.txt +++ b/third_party/blink/web_tests/accessibility/clickable-expected.txt
@@ -31,7 +31,7 @@ PASS isAXElementClickable('mousedown-listener') is true PASS isAXElementClickable('click-listener-on-ancestor') is false PASS axRole('ancestor-with-click-listener') is 'AXRole: AXGenericContainer' -PASS axRole('empty-anchor') is 'AXRole: AXAnchor' +PASS axRole('empty-anchor') is 'AXRole: AXGenericContainer' PASS axRole('href-anchor') is 'AXRole: AXLink' PASS axRole('onclick-anchor') is 'AXRole: AXLink' PASS axRole('click-listener-anchor') is 'AXRole: AXLink'
diff --git a/third_party/blink/web_tests/accessibility/clickable.html b/third_party/blink/web_tests/accessibility/clickable.html index 4c9f50b..ea7ca74 100644 --- a/third_party/blink/web_tests/accessibility/clickable.html +++ b/third_party/blink/web_tests/accessibility/clickable.html
@@ -94,7 +94,7 @@ shouldBe("isAXElementClickable('click-listener-on-ancestor')", "false"); shouldBe("axRole('ancestor-with-click-listener')", "'AXRole: AXGenericContainer'"); - shouldBe("axRole('empty-anchor')", "'AXRole: AXAnchor'"); + shouldBe("axRole('empty-anchor')", "'AXRole: AXGenericContainer'"); shouldBe("axRole('href-anchor')", "'AXRole: AXLink'"); shouldBe("axRole('onclick-anchor')", "'AXRole: AXLink'"); shouldBe("axRole('click-listener-anchor')", "'AXRole: AXLink'");
diff --git a/third_party/blink/web_tests/accessibility/continuation3.html b/third_party/blink/web_tests/accessibility/continuation3.html deleted file mode 100644 index a6e7ad9..0000000 --- a/third_party/blink/web_tests/accessibility/continuation3.html +++ /dev/null
@@ -1,26 +0,0 @@ -<!DOCTYPE HTML> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> - -<div> - <span> - <a name="a"> - <div id="before">Before</div> - <div id="ever"> - Ever - <a href="#" id="after">After</a> - </div> - </a> - </span> -</div> - -<script> -test(function(t) { - var axBefore = accessibilityController.accessibleElementById("before"); - assert_equals(axBefore.childAtIndex(0).name, "Before"); - var axEver = accessibilityController.accessibleElementById("ever"); - assert_equals(axEver.childAtIndex(0).name, "Ever "); - var axAfter = accessibilityController.accessibleElementById("after"); - assert_equals(axAfter.name, "After"); -}, "Ensure that continuations are included in the accessibility tree."); -</script>
diff --git a/third_party/blink/web_tests/accessibility/in-page-link-target.html b/third_party/blink/web_tests/accessibility/in-page-link-target.html index dadb2eed..6ae7e47 100644 --- a/third_party/blink/web_tests/accessibility/in-page-link-target.html +++ b/third_party/blink/web_tests/accessibility/in-page-link-target.html
@@ -24,9 +24,9 @@ assert_not_equals(anchor, undefined); var target = anchor.inPageLinkTarget; assert_not_equals(target, undefined); - // AXAncor because this is how the "a" tag is marked in the accessibility tree + // AXGenericContainer because this is how the "a" tag is marked in the AX tree // when it's a target and not a link. - assert_equals(target.role, 'AXRole: AXAnchor'); + assert_equals(target.role, 'AXRole: AXGenericContainer'); assert_equals(target.name, ''); }, 'Test finding the target when it is an empty anchor.'); @@ -35,10 +35,9 @@ assert_not_equals(anchor, undefined); var target = anchor.inPageLinkTarget; assert_not_equals(target, undefined); - // AXAncor because this is how the "a" tag is marked in the accessibility tree + // AXGenericContainer because this is how the "a" tag is marked in the AX tree // when it's a target and not a link. - assert_equals(target.role, 'AXRole: AXAnchor'); - assert_equals(target.name, 'Anchor with content'); + assert_equals(target.role, 'AXRole: AXGenericContainer'); }, 'Test finding the target when it is an anchor with content.'); test(function() { @@ -46,10 +45,9 @@ assert_not_equals(anchor, undefined); var target = anchor.inPageLinkTarget; assert_not_equals(target, undefined); - // AXAncor because this is how the "a" tag is marked in the accessibility tree + // AXGenericContainer because this is how the "a" tag is marked in the AX tree // when it's a target and not a link. - assert_equals(target.role, 'AXRole: AXAnchor'); - assert_equals(target.name, 'Anchor with ID'); + assert_equals(target.role, 'AXRole: AXGenericContainer'); }, 'Test finding the target when it is an anchor with ID.'); test(function() {
diff --git a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations index 59d02c5..d3e1699a3 100644 --- a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations +++ b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
@@ -1708,7 +1708,6 @@ crbug.com/1050754 external/wpt/uievents/click/auxclick_event.html [ Timeout ] crbug.com/1050754 external/wpt/uievents/click/click_events_on_input.html [ Crash Failure Pass ] crbug.com/1050754 external/wpt/uievents/idlharness.window.html [ Failure Pass ] -crbug.com/1050754 external/wpt/uievents/interface/keyboard-accesskey-click-event.html [ Pass ] crbug.com/1050754 external/wpt/uievents/keyboard/modifier-keys-combinations.html [ Pass ] crbug.com/1050754 external/wpt/uievents/keyboard/modifier-keys.html [ Pass ] crbug.com/1050754 external/wpt/uievents/order-of-events/focus-events/focus-contained.html [ Pass Timeout ] @@ -2281,3 +2280,9 @@ crbug.com/1050754 external/wpt/resource-timing/sizes-redirect.any.sharedworker.html [ Failure ] crbug.com/1050754 external/wpt/web-bundle/subresource-loading/csp-blocked.https.tentative.html [ Failure ] crbug.com/1050754 external/wpt/video-rvfc/request-video-frame-callback.html [ Timeout ] + +# update on 06/03/2021 +crbug.com/1050754 external/wpt/html/cross-origin-embedder-policy/credentialless/reporting-subresource-corp.tentative.https.html [ Failure ] +crbug.com/1050754 external/wpt/html/cross-origin-embedder-policy/reporting-to-endpoint.https.html [ Failure ] +crbug.com/1050754 external/wpt/uievents/interface/keyboard-accesskey-click-event.html [ Pass Failure ] +crbug.com/1050754 external/wpt/webcodecs/image-decoder.any.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/accessibility/crashtests/content-visibility-generated-content-removal.html b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/content-visibility-generated-content-removal.html new file mode 100644 index 0000000..b880e24 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/content-visibility-generated-content-removal.html
@@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html class="test-wait"> +<style> + div { content-visibility: auto; } + div::after { content: "Bar" } +</style> +<div>Foo</div> +<div style="height:4000px"></div> +<script> + // Ensure no crash when removing element with generated content after + // `content-visibility: auto` content goes out of view. + requestAnimationFrame(() => { + requestAnimationFrame(() => { + // Let one layout run with the div content in view, then + // scroll it out of view. + document.scrollingElement.scrollTop = 3000; + + // Run three frames to ensure a new layout happens with the + // 'auto' content hidden (i.e. layout structures are + // destroyed), then remove the div with a pseudo element which + // was previously problematic. + requestAnimationFrame(() => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + document.querySelector('div').remove(); + document.documentElement.className = ''; + }) + }) + }) + }) + }); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-001.html new file mode 100644 index 0000000..ebed26b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-001.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-overview"> +<meta name="assert" content="Tests the min-content contribution is using the correct block-size."> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="display: inline-grid; background: green; height: 100px; grid-template-rows: 50px;"> + <div style="height: 100%;"> <!-- This height should resolve against 50px - not 100px --> + <canvas width="20" height="10" style="height: 100%;"> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-002.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-002.tentative.html new file mode 100644 index 0000000..abf175d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-002.tentative.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-overview"> +<meta name="assert" content="Tests the min-content contribution is re-resolved during a 2nd pass."> +<!-- + +" + Then, if the min-content contribution of any grid item has changed based on + the row sizes and alignment calculated in step 2, re-resolve the sizes of the + grid columns with the new min-content and max-content contributions (once + only). +" + +In this testcase initially the row size is indefinite, then resolves to 100px. +Using this information we re-resolve the columns, resulting in 100px for the +first column. + +--> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="display: grid; width: 0; grid-template: auto / auto auto;"> + <div style="background: green; height: 100%;"> + <canvas width="10" height="10" style="height: 100%;"> + </div> + <div> + <div style="height: 100px;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-003.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-003.tentative.html new file mode 100644 index 0000000..0488165a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-inline-contribution-003.tentative.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#algo-overview"> +<meta name="assert" content="Tests the min-content contribution is re-resolved during a 2nd pass."> +<!-- + +" + Then, if the min-content contribution of any grid item has changed based on + the row sizes and alignment calculated in step 2, re-resolve the sizes of the + grid columns with the new min-content and max-content contributions (once + only). +" + +In this testcase initially the row size is indefinite, then resolves to 100px. +Using this information we re-resolve the columns, resulting in 100px for the +first column. + +--> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="display: grid; width: 0; grid-template: auto / auto auto;"> + <div style="background: green;"> <!-- Has stretch alignment which the child should resolve against. --> + <canvas width="10" height="10" style="height: 100%;"> + </div> + <div> + <div style="height: 100px;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-025-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-025-ref.html index f760a49..fbb1ce8 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-025-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-025-ref.html
@@ -15,10 +15,13 @@ grid-gap: 5px; } .one { - grid-template: none / 3fr 4fr; + grid-template: repeat(8, 10px) / 3fr 4fr; } .two { - grid-template: 1fr 2fr / none; + grid-template: 1fr 2fr / repeat(3, 15px); +} +.three { + grid-template: repeat(8, 10px) / repeat(3, 15px); } .item {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-026-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-026-ref.html index 8389ef70..3bf3a288 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-026-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/contain-intrinsic-size/contain-intrinsic-size-026-ref.html
@@ -8,6 +8,7 @@ .grid { display: inline-grid; border: 1px solid black; + grid-template-columns: repeat(auto-fit, 100px); height: 40px; } .one {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/td-box-sizing-003.html b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/td-box-sizing-003.html index 3eb78e7..40b0147 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/td-box-sizing-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/td-box-sizing-003.html
@@ -79,6 +79,19 @@ </tbody> </table> +<p>box-sizing: border-box;padding: px, width px</p> +<li>td's intrinsic width must be >= border + padding</li> + +<table style="width:300px;table-layout:fixed"> + <tbody> + <tr> + <td style="box-sizing:border-box;padding-left:50px;padding-right:50px;width:30px" data-expected-width=100></td> + <td>auto</td> + <td>auto</td> + </tr> + </tbody> +</table> + <p>box-sizing: border-box; border px; padding %.</p> <li>intrinsic size of % padding is 0. <li>final size of % padding is computed against table's width. @@ -127,6 +140,8 @@ </td> </tr> </table> + + </main> <script> checkLayout("table");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/idlharness-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-typed-om/idlharness-expected.txt index 4b3bdb9..cd96b17 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/idlharness-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/idlharness-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 510 tests; 433 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 508 tests; 431 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS Partial interface Element: original interface defined @@ -398,13 +398,8 @@ FAIL CSSColorValue interface: existence and properties of interface prototype object assert_equals: prototype of CSSColorValue.prototype is not CSSStyleValue.prototype expected [stringifying object threw TypeError: Illegal invocation with type object] but got object "[object Object]" PASS CSSColorValue interface: existence and properties of interface prototype object's "constructor" property PASS CSSColorValue interface: existence and properties of interface prototype object's @@unscopables property -PASS CSSColorValue interface: operation toRGB() -PASS CSSColorValue interface: operation toHSL() -FAIL CSSColorValue interface: operation toHWB() assert_own_property: interface prototype object missing non-static operation expected property "toHWB" missing -FAIL CSSColorValue interface: operation toGray() assert_own_property: interface prototype object missing non-static operation expected property "toGray" missing -FAIL CSSColorValue interface: operation toLCH() assert_own_property: interface prototype object missing non-static operation expected property "toLCH" missing -FAIL CSSColorValue interface: operation toLab() assert_own_property: interface prototype object missing non-static operation expected property "toLab" missing -FAIL CSSColorValue interface: operation toColor(CSSKeywordish) assert_own_property: interface prototype object missing non-static operation expected property "toColor" missing +FAIL CSSColorValue interface: attribute colorSpace assert_true: The prototype object must have a property "colorSpace" expected true got false +FAIL CSSColorValue interface: operation to(CSSKeywordish) assert_own_property: interface prototype object missing non-static operation expected property "to" missing FAIL CSSColorValue interface: operation parse(USVString) assert_own_property: interface object missing static operation expected property "parse" missing PASS CSSRGB interface: existence and properties of interface object PASS CSSRGB interface object length @@ -436,14 +431,6 @@ FAIL CSSHWB interface: attribute w assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing FAIL CSSHWB interface: attribute b assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing FAIL CSSHWB interface: attribute alpha assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing -FAIL CSSGray interface: existence and properties of interface object assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface object length assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface object name assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface: attribute gray assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing -FAIL CSSGray interface: attribute alpha assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing FAIL CSSLCH interface: existence and properties of interface object assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing FAIL CSSLCH interface object length assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing FAIL CSSLCH interface object name assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing @@ -470,6 +457,17 @@ FAIL CSSColor interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing FAIL CSSColor interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing FAIL CSSColor interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSDeviceCMYK interface: existence and properties of interface object assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface object length assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface object name assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: attribute c assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: attribute m assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: attribute y assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: attribute k assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing +FAIL CSSDeviceCMYK interface: attribute alpha assert_own_property: self does not have own property "CSSDeviceCMYK" expected property "CSSDeviceCMYK" missing PASS CSSStyleRule interface: attribute styleMap PASS CSS namespace: operation escape(CSSOMString) PASS CSS namespace: operation number(double)
diff --git "a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_exclude=\050Document_Window_HTML._\051-expected.txt" "b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_exclude=\050Document_Window_HTML._\051-expected.txt" index f3fcb35c..8332c366 100644 --- "a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_exclude=\050Document_Window_HTML._\051-expected.txt" +++ "b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_exclude=\050Document_Window_HTML._\051-expected.txt"
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 1441 tests; 1410 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 1445 tests; 1414 PASS, 31 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS Partial interface Document: original interface defined @@ -448,6 +448,7 @@ PASS CanvasRenderingContext2D interface: attribute fillStyle PASS CanvasRenderingContext2D interface: operation createLinearGradient(double, double, double, double) PASS CanvasRenderingContext2D interface: operation createRadialGradient(double, double, double, double, double, double) +PASS CanvasRenderingContext2D interface: operation createConicGradient(double, double, double) PASS CanvasRenderingContext2D interface: operation createPattern(CanvasImageSource, DOMString) PASS CanvasRenderingContext2D interface: attribute shadowOffsetX PASS CanvasRenderingContext2D interface: attribute shadowOffsetY @@ -540,6 +541,8 @@ PASS CanvasRenderingContext2D interface: calling createLinearGradient(double, double, double, double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError PASS CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "createRadialGradient(double, double, double, double, double, double)" with the proper type PASS CanvasRenderingContext2D interface: calling createRadialGradient(double, double, double, double, double, double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError +PASS CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "createConicGradient(double, double, double)" with the proper type +PASS CanvasRenderingContext2D interface: calling createConicGradient(double, double, double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError PASS CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "createPattern(CanvasImageSource, DOMString)" with the proper type PASS CanvasRenderingContext2D interface: calling createPattern(CanvasImageSource, DOMString) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError PASS CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "shadowOffsetX" with the proper type @@ -747,6 +750,7 @@ PASS OffscreenCanvasRenderingContext2D interface: attribute fillStyle PASS OffscreenCanvasRenderingContext2D interface: operation createLinearGradient(double, double, double, double) PASS OffscreenCanvasRenderingContext2D interface: operation createRadialGradient(double, double, double, double, double, double) +PASS OffscreenCanvasRenderingContext2D interface: operation createConicGradient(double, double, double) PASS OffscreenCanvasRenderingContext2D interface: operation createPattern(CanvasImageSource, DOMString) PASS OffscreenCanvasRenderingContext2D interface: attribute shadowOffsetX PASS OffscreenCanvasRenderingContext2D interface: attribute shadowOffsetY
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.worker-expected.txt b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.worker-expected.txt index 260003c..4900aac 100644 --- a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 804 tests; 796 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 805 tests; 797 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS Partial interface Document: original interface defined @@ -358,6 +358,7 @@ PASS OffscreenCanvasRenderingContext2D interface: attribute fillStyle PASS OffscreenCanvasRenderingContext2D interface: operation createLinearGradient(double, double, double, double) PASS OffscreenCanvasRenderingContext2D interface: operation createRadialGradient(double, double, double, double, double, double) +PASS OffscreenCanvasRenderingContext2D interface: operation createConicGradient(double, double, double) PASS OffscreenCanvasRenderingContext2D interface: operation createPattern(CanvasImageSource, DOMString) PASS OffscreenCanvasRenderingContext2D interface: attribute shadowOffsetX PASS OffscreenCanvasRenderingContext2D interface: attribute shadowOffsetY
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/newline-normalization-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/newline-normalization-expected.txt new file mode 100644 index 0000000..fa7284e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-submission-0/newline-normalization-expected.txt
@@ -0,0 +1,15 @@ +This is a testharness.js-based test. +FAIL Constructing the entry list shouldn't perform newline normalization: \n in the value assert_equals: expected "b\nc" but got "b\r\nc" +FAIL Constructing the entry list shouldn't perform newline normalization: \r in the value assert_equals: expected "b\rc" but got "b\r\nc" +PASS Constructing the entry list shouldn't perform newline normalization: \r\n in the value +FAIL Constructing the entry list shouldn't perform newline normalization: \n\r in the value assert_equals: expected "b\n\rc" but got "b\r\n\r\nc" +FAIL Constructing the entry list shouldn't perform newline normalization: \n in the name assert_equals: expected "a\nb" but got "a\r\nb" +FAIL Constructing the entry list shouldn't perform newline normalization: \r in the name assert_equals: expected "a\rb" but got "a\r\nb" +PASS Constructing the entry list shouldn't perform newline normalization: \r\n in the name +FAIL Constructing the entry list shouldn't perform newline normalization: \n\r in the name assert_equals: expected "a\n\rb" but got "a\r\n\r\nb" +PASS Constructing the entry list shouldn't perform newline normalization: \n in the filename +PASS Constructing the entry list shouldn't perform newline normalization: \r in the filename +PASS Constructing the entry list shouldn't perform newline normalization: \r\n in the filename +PASS Constructing the entry list shouldn't perform newline normalization: \n\r in the filename +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-textarea-element/wrapping-transformation.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-textarea-element/wrapping-transformation.window-expected.txt new file mode 100644 index 0000000..0c63131a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-textarea-element/wrapping-transformation.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Textarea wrapping transformation: Newlines should be normalized to LF. assert_equals: expected "a\nb\nc\nd\n\ne" but got "a\r\nb\r\nc\r\nd\r\n\r\ne" +FAIL Textarea wrapping transformation: Wrapping happens with LF newlines. assert_true: The wrapping done on the value must be LF, not CRLF. expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt index 0c26f729..3b829c2 100644 --- a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 114 tests; 71 PASS, 43 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 99 tests; 66 PASS, 33 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS Partial interface ServiceWorkerRegistration: original interface defined @@ -17,13 +17,10 @@ FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing -FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager must be primary interface of paymentManager assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing PASS Stringification of paymentManager PASS PaymentManager interface: paymentManager must inherit property "instruments" with the proper type PASS PaymentManager interface: paymentManager must inherit property "userHint" with the proper type -PASS PaymentManager interface: paymentManager must inherit property "enableDelegations(sequence<PaymentDelegation>)" with the proper type -PASS PaymentManager interface: calling enableDelegations(sequence<PaymentDelegation>) on paymentManager with too few arguments must throw TypeError PASS PaymentInstruments interface: existence and properties of interface object PASS PaymentInstruments interface object length PASS PaymentInstruments interface object name @@ -78,13 +75,8 @@ PASS PaymentRequestEvent interface: attribute total PASS PaymentRequestEvent interface: attribute modifiers PASS PaymentRequestEvent interface: attribute instrumentKey -FAIL PaymentRequestEvent interface: attribute requestBillingAddress assert_true: The prototype object must have a property "requestBillingAddress" expected true got false -PASS PaymentRequestEvent interface: attribute paymentOptions -PASS PaymentRequestEvent interface: attribute shippingOptions PASS PaymentRequestEvent interface: operation openWindow(USVString) PASS PaymentRequestEvent interface: operation changePaymentMethod(DOMString, optional object?) -FAIL PaymentRequestEvent interface: operation changeShippingAddress(optional AddressInit) assert_equals: property has wrong .length expected 0 but got 1 -PASS PaymentRequestEvent interface: operation changeShippingOption(DOMString) PASS PaymentRequestEvent interface: operation respondWith(Promise<PaymentHandlerResponse>) FAIL PaymentRequestEvent must be primary interface of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL Stringification of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." @@ -95,17 +87,10 @@ FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "total" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "modifiers" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "instrumentKey" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "requestBillingAddress" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentOptions" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "shippingOptions" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "openWindow(USVString)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: calling openWindow(USVString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changePaymentMethod(DOMString, optional object?)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: calling changePaymentMethod(DOMString, optional object?) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingAddress(optional AddressInit)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: calling changeShippingAddress(optional AddressInit) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingOption(DOMString)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." -FAIL PaymentRequestEvent interface: calling changeShippingOption(DOMString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "respondWith(Promise<PaymentHandlerResponse>)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL PaymentRequestEvent interface: calling respondWith(Promise<PaymentHandlerResponse>) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." PASS ServiceWorkerRegistration interface: attribute paymentManager
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt index 2ee5817..b282125 100644 --- a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt
@@ -16,7 +16,6 @@ FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing -FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing PASS PaymentInstruments interface: existence and properties of interface object PASS PaymentInstruments interface object length PASS PaymentInstruments interface object name
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt index 2ee5817..b282125 100644 --- a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt
@@ -16,7 +16,6 @@ FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing -FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing PASS PaymentInstruments interface: existence and properties of interface object PASS PaymentInstruments interface object length PASS PaymentInstruments interface object name
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/idlharness.https.window-expected.txt index dd488a1..df50505 100644 --- a/third_party/blink/web_tests/external/wpt/payment-request/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-request/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 91 tests; 90 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 75 tests; 74 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS PaymentRequest interface: existence and properties of interface object @@ -12,11 +12,6 @@ PASS PaymentRequest interface: operation abort() PASS PaymentRequest interface: operation canMakePayment() PASS PaymentRequest interface: attribute id -PASS PaymentRequest interface: attribute shippingAddress -PASS PaymentRequest interface: attribute shippingOption -PASS PaymentRequest interface: attribute shippingType -PASS PaymentRequest interface: attribute onshippingaddresschange -PASS PaymentRequest interface: attribute onshippingoptionchange PASS PaymentRequest interface: attribute onpaymentmethodchange PASS PaymentRequest must be primary interface of paymentRequest PASS Stringification of paymentRequest @@ -25,29 +20,7 @@ PASS PaymentRequest interface: paymentRequest must inherit property "abort()" with the proper type PASS PaymentRequest interface: paymentRequest must inherit property "canMakePayment()" with the proper type PASS PaymentRequest interface: paymentRequest must inherit property "id" with the proper type -PASS PaymentRequest interface: paymentRequest must inherit property "shippingAddress" with the proper type -PASS PaymentRequest interface: paymentRequest must inherit property "shippingOption" with the proper type -PASS PaymentRequest interface: paymentRequest must inherit property "shippingType" with the proper type -PASS PaymentRequest interface: paymentRequest must inherit property "onshippingaddresschange" with the proper type -PASS PaymentRequest interface: paymentRequest must inherit property "onshippingoptionchange" with the proper type PASS PaymentRequest interface: paymentRequest must inherit property "onpaymentmethodchange" with the proper type -PASS PaymentAddress interface: existence and properties of interface object -PASS PaymentAddress interface object length -PASS PaymentAddress interface object name -PASS PaymentAddress interface: existence and properties of interface prototype object -PASS PaymentAddress interface: existence and properties of interface prototype object's "constructor" property -PASS PaymentAddress interface: existence and properties of interface prototype object's @@unscopables property -PASS PaymentAddress interface: operation toJSON() -PASS PaymentAddress interface: attribute city -PASS PaymentAddress interface: attribute country -PASS PaymentAddress interface: attribute dependentLocality -PASS PaymentAddress interface: attribute organization -PASS PaymentAddress interface: attribute phone -PASS PaymentAddress interface: attribute postalCode -PASS PaymentAddress interface: attribute recipient -PASS PaymentAddress interface: attribute region -PASS PaymentAddress interface: attribute sortingCode -PASS PaymentAddress interface: attribute addressLine PASS PaymentResponse interface: existence and properties of interface object PASS PaymentResponse interface object length PASS PaymentResponse interface object name @@ -58,14 +31,8 @@ PASS PaymentResponse interface: attribute requestId PASS PaymentResponse interface: attribute methodName PASS PaymentResponse interface: attribute details -PASS PaymentResponse interface: attribute shippingAddress -PASS PaymentResponse interface: attribute shippingOption -PASS PaymentResponse interface: attribute payerName -PASS PaymentResponse interface: attribute payerEmail -PASS PaymentResponse interface: attribute payerPhone PASS PaymentResponse interface: operation complete(optional PaymentComplete) PASS PaymentResponse interface: operation retry(optional PaymentValidationErrors) -PASS PaymentResponse interface: attribute onpayerdetailchange PASS PaymentMethodChangeEvent interface: existence and properties of interface object PASS PaymentMethodChangeEvent interface object length PASS PaymentMethodChangeEvent interface object name @@ -91,5 +58,22 @@ PASS Stringification of new PaymentRequestUpdateEvent("paymentrequestupdate") PASS PaymentRequestUpdateEvent interface: new PaymentRequestUpdateEvent("paymentrequestupdate") must inherit property "updateWith(Promise<PaymentDetailsUpdate>)" with the proper type PASS PaymentRequestUpdateEvent interface: calling updateWith(Promise<PaymentDetailsUpdate>) on new PaymentRequestUpdateEvent("paymentrequestupdate") with too few arguments must throw TypeError +PASS PaymentAddress interface: existence and properties of interface object +PASS PaymentAddress interface object length +PASS PaymentAddress interface object name +PASS PaymentAddress interface: existence and properties of interface prototype object +PASS PaymentAddress interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentAddress interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentAddress interface: operation toJSON() +PASS PaymentAddress interface: attribute city +PASS PaymentAddress interface: attribute country +PASS PaymentAddress interface: attribute dependentLocality +PASS PaymentAddress interface: attribute organization +PASS PaymentAddress interface: attribute phone +PASS PaymentAddress interface: attribute postalCode +PASS PaymentAddress interface: attribute recipient +PASS PaymentAddress interface: attribute region +PASS PaymentAddress interface: attribute sortingCode +PASS PaymentAddress interface: attribute addressLine Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/private-click-measurement/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/private-click-measurement/idlharness.window-expected.txt new file mode 100644 index 0000000..046f895 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/private-click-measurement/idlharness.window-expected.txt
@@ -0,0 +1,21 @@ +This is a testharness.js-based test. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface HTMLAnchorElement: original interface defined +PASS Partial interface HTMLAnchorElement: member names are unique +PASS Partial interface HTMLAnchorElement[2]: member names are unique +PASS HTMLElement includes GlobalEventHandlers: member names are unique +PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique +PASS HTMLElement includes ElementContentEditable: member names are unique +PASS HTMLElement includes HTMLOrSVGElement: member names are unique +PASS HTMLAnchorElement includes HTMLHyperlinkElementUtils: member names are unique +PASS Element includes ParentNode: member names are unique +PASS Element includes NonDocumentTypeChildNode: member names are unique +PASS Element includes ChildNode: member names are unique +PASS Element includes Slottable: member names are unique +FAIL HTMLAnchorElement interface: attribute attributionSourceId assert_true: The prototype object must have a property "attributionSourceId" expected true got false +PASS HTMLAnchorElement interface: attribute attributionDestination +FAIL HTMLAnchorElement interface: document.createElement("a") must inherit property "attributionSourceId" with the proper type assert_inherits: property "attributionSourceId" not found in prototype chain +PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "attributionDestination" with the proper type +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt index ce5ff0d0..010886b 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 77 tests; 70 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 75 tests; 70 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS getStats succeeds PASS Validating stats PASS RTCRtpStreamStats's ssrc @@ -49,7 +49,6 @@ PASS RTCVideoSourceStats's framesPerSecond FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false PASS RTCCodecStats's payloadType -FAIL RTCCodecStats's codecType assert_true: Is codecType present expected true got false PASS RTCCodecStats's mimeType PASS RTCCodecStats's clockRate PASS RTCCodecStats's channels @@ -76,6 +75,5 @@ PASS RTCCertificateStats's fingerprint PASS RTCCertificateStats's fingerprintAlgorithm PASS RTCCertificateStats's base64Certificate -FAIL RTCCertificateStats's issuerCertificateId assert_true: Is issuerCertificateId present expected true got false Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt index f514bf73..585d803 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: stable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 -FAIL setLocalDescription(pranswer) should succeed assert_equals: expected null but got object "[object RTCSessionDescription]" +PASS setLocalDescription(pranswer) should succeed PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer PASS setLocalDescription(answer) from have-local-pranswer state should succeed Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt index bd78477..d7675f0 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 281 tests; 270 PASS, 11 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 283 tests; 270 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS idl_test validation PASS Partial interface Navigator: original interface defined @@ -215,6 +215,7 @@ PASS XRWebGLLayer interface: existence and properties of interface prototype object's @@unscopables property PASS XRWebGLLayer interface: attribute antialias PASS XRWebGLLayer interface: attribute ignoreDepthValues +FAIL XRWebGLLayer interface: attribute fixedFoveation assert_true: The prototype object must have a property "fixedFoveation" expected true got false PASS XRWebGLLayer interface: attribute framebuffer PASS XRWebGLLayer interface: attribute framebufferWidth PASS XRWebGLLayer interface: attribute framebufferHeight @@ -224,6 +225,7 @@ PASS Stringification of xrWebGLLayer PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "antialias" with the proper type PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "ignoreDepthValues" with the proper type +FAIL XRWebGLLayer interface: xrWebGLLayer must inherit property "fixedFoveation" with the proper type assert_inherits: property "fixedFoveation" not found in prototype chain PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebuffer" with the proper type PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebufferWidth" with the proper type PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebufferHeight" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/xhr/formdata/constructor-formelement-expected.txt b/third_party/blink/web_tests/external/wpt/xhr/formdata/constructor-formelement-expected.txt new file mode 100644 index 0000000..6d375ee --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/xhr/formdata/constructor-formelement-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL test that FormData is correctly constructed from the form data set assert_array_equals: submit-me-16 expected property 0 to be "textarea value\nwith linebreaks set to LF" but got "textarea value\r\nwith linebreaks set to LF" (expected array ["textarea value\nwith linebreaks set to LF"] got ["textarea value\r\nwith linebreaks set to LF"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-all-on-background-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-all-on-background-hw-expected.png new file mode 100644 index 0000000..2dccb00 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-all-on-background-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-clamping-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-clamping-hw-expected.png new file mode 100644 index 0000000..26e9b80 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-clamping-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-hw-expected.png new file mode 100644 index 0000000..ce7e6a7 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-brightness-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-combined-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-combined-hw-expected.png new file mode 100644 index 0000000..e8f25ee --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-combined-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-contrast-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-contrast-hw-expected.png new file mode 100644 index 0000000..bb0f665 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-contrast-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-grayscale-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-grayscale-hw-expected.png new file mode 100644 index 0000000..440bc23 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-grayscale-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-hue-rotate-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-hue-rotate-hw-expected.png new file mode 100644 index 0000000..f2a8f3e --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-hue-rotate-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-invert-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-invert-hw-expected.png new file mode 100644 index 0000000..8933d61 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-invert-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-opacity-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-opacity-hw-expected.png new file mode 100644 index 0000000..9b01b9e --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-opacity-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png index eb0f3a3..b8c6179 100644 --- a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png index 8c86a07..5b428dd 100644 --- a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-saturate-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-saturate-hw-expected.png new file mode 100644 index 0000000..7d5a881 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-saturate-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-sepia-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-sepia-hw-expected.png new file mode 100644 index 0000000..e673696 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-use-zoom-for-dsf/platform/mac/virtual/scalefactor200/css3/filters/effect-sepia-hw-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window-expected.txt index 21d9d9d..9a71787 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 413 tests; 253 PASS, 160 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 413 tests; 255 PASS, 158 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. @@ -388,9 +388,9 @@ PASS <a>: Setting <https://example.net>.search = '' PASS <area>: Setting <https://example.net>.search = '' FAIL <a>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" FAIL <area>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS <a>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <area>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <a>: Setting <https://example.net>.hash = 'main' @@ -415,10 +415,10 @@ PASS <area>: Setting <http://example.net>.hash = '#foo>bar' PASS <a>: Setting <http://example.net>.hash = '#foo`bar' PASS <area>: Setting <http://example.net>.hash = '#foo`bar' -FAIL <a>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" -FAIL <area>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS <a>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed +PASS <area>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS <a>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <area>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <a>: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any-expected.txt index 326d569..92293f7 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 207 tests; 130 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS URL: Setting <a://example.net>.protocol = 'b' @@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -208,8 +208,8 @@ PASS URL: Setting <http://example.net>.hash = '#foo<bar' PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' -FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker-expected.txt index 326d569..92293f7 100644 --- a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 207 tests; 130 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS URL: Setting <a://example.net>.protocol = 'b' @@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -208,8 +208,8 @@ PASS URL: Setting <http://example.net>.hash = '#foo<bar' PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' -FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png index 88b1a61..ca09d30e 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png index 3a75210..4c82445 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png index 18e4369..3ea3de64 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png index d8b4a1b..8f8dcef 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/text-gradient-positioning-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/text-gradient-positioning-expected.png index 20e2a7f2..c1f26b0 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/text-gradient-positioning-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/text-gradient-positioning-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-typed-om/idlharness-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-typed-om/idlharness-expected.txt new file mode 100644 index 0000000..4b3bdb9 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/css/css-typed-om/idlharness-expected.txt
@@ -0,0 +1,514 @@ +This is a testharness.js-based test. +Found 510 tests; 433 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface Element: original interface defined +PASS Partial interface Element: member names are unique +PASS Partial interface CSSStyleRule: original interface defined +PASS Partial interface CSSStyleRule: member names are unique +PASS Partial interface mixin ElementCSSInlineStyle: original interface mixin defined +PASS Partial interface mixin ElementCSSInlineStyle: member names are unique +PASS Partial namespace CSS: original namespace defined +PASS Partial namespace CSS: member names are unique +PASS HTMLElement includes ElementCSSInlineStyle: member names are unique +PASS SVGElement includes ElementCSSInlineStyle: member names are unique +PASS MathMLElement includes ElementCSSInlineStyle: member names are unique +PASS SVGElement includes GlobalEventHandlers: member names are unique +PASS SVGElement includes DocumentAndElementEventHandlers: member names are unique +PASS SVGElement includes SVGElementInstance: member names are unique +PASS SVGElement includes HTMLOrSVGElement: member names are unique +PASS HTMLElement includes GlobalEventHandlers: member names are unique +PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique +PASS HTMLElement includes ElementContentEditable: member names are unique +PASS HTMLElement includes HTMLOrSVGElement: member names are unique +PASS Element includes ParentNode: member names are unique +PASS Element includes NonDocumentTypeChildNode: member names are unique +PASS Element includes ChildNode: member names are unique +PASS Element includes Slottable: member names are unique +PASS MathMLElement includes GlobalEventHandlers: member names are unique +PASS MathMLElement includes DocumentAndElementEventHandlers: member names are unique +PASS MathMLElement includes HTMLOrSVGElement: member names are unique +PASS CSSStyleValue interface: existence and properties of interface object +PASS CSSStyleValue interface object length +PASS CSSStyleValue interface object name +PASS CSSStyleValue interface: existence and properties of interface prototype object +PASS CSSStyleValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSStyleValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSStyleValue interface: stringifier +PASS CSSStyleValue interface: operation parse(USVString, USVString) +PASS CSSStyleValue interface: operation parseAll(USVString, USVString) +PASS StylePropertyMapReadOnly interface: existence and properties of interface object +PASS StylePropertyMapReadOnly interface object length +PASS StylePropertyMapReadOnly interface object name +PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object +PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object's "constructor" property +PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object's @@unscopables property +PASS StylePropertyMapReadOnly interface: iterable<USVString, [object Object]> +PASS StylePropertyMapReadOnly interface: operation get(USVString) +PASS StylePropertyMapReadOnly interface: operation getAll(USVString) +PASS StylePropertyMapReadOnly interface: operation has(USVString) +PASS StylePropertyMapReadOnly interface: attribute size +PASS StylePropertyMap interface: existence and properties of interface object +PASS StylePropertyMap interface object length +PASS StylePropertyMap interface object name +PASS StylePropertyMap interface: existence and properties of interface prototype object +PASS StylePropertyMap interface: existence and properties of interface prototype object's "constructor" property +PASS StylePropertyMap interface: existence and properties of interface prototype object's @@unscopables property +PASS StylePropertyMap interface: operation set(USVString, (CSSStyleValue or USVString)...) +PASS StylePropertyMap interface: operation append(USVString, (CSSStyleValue or USVString)...) +PASS StylePropertyMap interface: operation delete(USVString) +PASS StylePropertyMap interface: operation clear() +PASS StylePropertyMap must be primary interface of styleMap +PASS Stringification of styleMap +PASS StylePropertyMap interface: styleMap must inherit property "set(USVString, (CSSStyleValue or USVString)...)" with the proper type +PASS StylePropertyMap interface: calling set(USVString, (CSSStyleValue or USVString)...) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMap interface: styleMap must inherit property "append(USVString, (CSSStyleValue or USVString)...)" with the proper type +PASS StylePropertyMap interface: calling append(USVString, (CSSStyleValue or USVString)...) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMap interface: styleMap must inherit property "delete(USVString)" with the proper type +PASS StylePropertyMap interface: calling delete(USVString) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMap interface: styleMap must inherit property "clear()" with the proper type +PASS StylePropertyMapReadOnly interface: styleMap must inherit property "get(USVString)" with the proper type +PASS StylePropertyMapReadOnly interface: calling get(USVString) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMapReadOnly interface: styleMap must inherit property "getAll(USVString)" with the proper type +PASS StylePropertyMapReadOnly interface: calling getAll(USVString) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMapReadOnly interface: styleMap must inherit property "has(USVString)" with the proper type +PASS StylePropertyMapReadOnly interface: calling has(USVString) on styleMap with too few arguments must throw TypeError +PASS StylePropertyMapReadOnly interface: styleMap must inherit property "size" with the proper type +PASS CSSUnparsedValue interface: existence and properties of interface object +PASS CSSUnparsedValue interface object length +PASS CSSUnparsedValue interface object name +PASS CSSUnparsedValue interface: existence and properties of interface prototype object +PASS CSSUnparsedValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSUnparsedValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSUnparsedValue interface: iterable<CSSUnparsedSegment> +PASS CSSUnparsedValue interface: attribute length +PASS CSSVariableReferenceValue interface: existence and properties of interface object +PASS CSSVariableReferenceValue interface object length +PASS CSSVariableReferenceValue interface object name +PASS CSSVariableReferenceValue interface: existence and properties of interface prototype object +PASS CSSVariableReferenceValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSVariableReferenceValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSVariableReferenceValue interface: attribute variable +PASS CSSVariableReferenceValue interface: attribute fallback +PASS CSSKeywordValue interface: existence and properties of interface object +PASS CSSKeywordValue interface object length +PASS CSSKeywordValue interface object name +PASS CSSKeywordValue interface: existence and properties of interface prototype object +PASS CSSKeywordValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSKeywordValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSKeywordValue interface: attribute value +PASS CSSNumericValue interface: existence and properties of interface object +PASS CSSNumericValue interface object length +PASS CSSNumericValue interface object name +PASS CSSNumericValue interface: existence and properties of interface prototype object +PASS CSSNumericValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSNumericValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSNumericValue interface: operation add(CSSNumberish...) +PASS CSSNumericValue interface: operation sub(CSSNumberish...) +PASS CSSNumericValue interface: operation mul(CSSNumberish...) +PASS CSSNumericValue interface: operation div(CSSNumberish...) +PASS CSSNumericValue interface: operation min(CSSNumberish...) +PASS CSSNumericValue interface: operation max(CSSNumberish...) +PASS CSSNumericValue interface: operation equals(CSSNumberish...) +PASS CSSNumericValue interface: operation to(USVString) +PASS CSSNumericValue interface: operation toSum(USVString...) +PASS CSSNumericValue interface: operation type() +PASS CSSNumericValue interface: operation parse(USVString) +PASS CSSUnitValue interface: existence and properties of interface object +PASS CSSUnitValue interface object length +PASS CSSUnitValue interface object name +PASS CSSUnitValue interface: existence and properties of interface prototype object +PASS CSSUnitValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSUnitValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSUnitValue interface: attribute value +PASS CSSUnitValue interface: attribute unit +PASS CSSUnitValue must be primary interface of unitValue +PASS Stringification of unitValue +PASS CSSUnitValue interface: unitValue must inherit property "value" with the proper type +PASS CSSUnitValue interface: unitValue must inherit property "unit" with the proper type +PASS CSSNumericValue interface: unitValue must inherit property "add(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling add(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "sub(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling sub(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "mul(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling mul(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "div(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling div(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "min(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling min(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "max(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling max(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "equals(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling equals(CSSNumberish...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "to(USVString)" with the proper type +PASS CSSNumericValue interface: calling to(USVString) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "toSum(USVString...)" with the proper type +PASS CSSNumericValue interface: calling toSum(USVString...) on unitValue with too few arguments must throw TypeError +PASS CSSNumericValue interface: unitValue must inherit property "type()" with the proper type +PASS CSSNumericValue interface: unitValue must inherit property "parse(USVString)" with the proper type +FAIL CSSNumericValue interface: calling parse(USVString) on unitValue with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parse" missing +PASS CSSStyleValue interface: unitValue must inherit property "parse(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parse(USVString, USVString) on unitValue with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parse" missing +PASS CSSStyleValue interface: unitValue must inherit property "parseAll(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parseAll(USVString, USVString) on unitValue with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parseAll" missing +PASS CSSMathValue interface: existence and properties of interface object +PASS CSSMathValue interface object length +PASS CSSMathValue interface object name +PASS CSSMathValue interface: existence and properties of interface prototype object +PASS CSSMathValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathValue interface: attribute operator +PASS CSSMathSum interface: existence and properties of interface object +PASS CSSMathSum interface object length +PASS CSSMathSum interface object name +PASS CSSMathSum interface: existence and properties of interface prototype object +PASS CSSMathSum interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathSum interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathSum interface: attribute values +PASS CSSMathSum must be primary interface of mathSum +PASS Stringification of mathSum +PASS CSSMathSum interface: mathSum must inherit property "values" with the proper type +PASS CSSMathValue interface: mathSum must inherit property "operator" with the proper type +PASS CSSNumericValue interface: mathSum must inherit property "add(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling add(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "sub(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling sub(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "mul(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling mul(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "div(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling div(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "min(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling min(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "max(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling max(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "equals(CSSNumberish...)" with the proper type +PASS CSSNumericValue interface: calling equals(CSSNumberish...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "to(USVString)" with the proper type +PASS CSSNumericValue interface: calling to(USVString) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "toSum(USVString...)" with the proper type +PASS CSSNumericValue interface: calling toSum(USVString...) on mathSum with too few arguments must throw TypeError +PASS CSSNumericValue interface: mathSum must inherit property "type()" with the proper type +PASS CSSNumericValue interface: mathSum must inherit property "parse(USVString)" with the proper type +FAIL CSSNumericValue interface: calling parse(USVString) on mathSum with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parse" missing +PASS CSSStyleValue interface: mathSum must inherit property "parse(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parse(USVString, USVString) on mathSum with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parse" missing +PASS CSSStyleValue interface: mathSum must inherit property "parseAll(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parseAll(USVString, USVString) on mathSum with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parseAll" missing +PASS CSSMathProduct interface: existence and properties of interface object +PASS CSSMathProduct interface object length +PASS CSSMathProduct interface object name +PASS CSSMathProduct interface: existence and properties of interface prototype object +PASS CSSMathProduct interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathProduct interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathProduct interface: attribute values +PASS CSSMathNegate interface: existence and properties of interface object +PASS CSSMathNegate interface object length +PASS CSSMathNegate interface object name +PASS CSSMathNegate interface: existence and properties of interface prototype object +PASS CSSMathNegate interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathNegate interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathNegate interface: attribute value +PASS CSSMathInvert interface: existence and properties of interface object +PASS CSSMathInvert interface object length +PASS CSSMathInvert interface object name +PASS CSSMathInvert interface: existence and properties of interface prototype object +PASS CSSMathInvert interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathInvert interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathInvert interface: attribute value +PASS CSSMathMin interface: existence and properties of interface object +PASS CSSMathMin interface object length +PASS CSSMathMin interface object name +PASS CSSMathMin interface: existence and properties of interface prototype object +PASS CSSMathMin interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathMin interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathMin interface: attribute values +PASS CSSMathMax interface: existence and properties of interface object +PASS CSSMathMax interface object length +PASS CSSMathMax interface object name +PASS CSSMathMax interface: existence and properties of interface prototype object +PASS CSSMathMax interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMathMax interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMathMax interface: attribute values +FAIL CSSMathClamp interface: existence and properties of interface object assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface object length assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface object name assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: attribute min assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: attribute val assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +FAIL CSSMathClamp interface: attribute max assert_own_property: self does not have own property "CSSMathClamp" expected property "CSSMathClamp" missing +PASS CSSNumericArray interface: existence and properties of interface object +PASS CSSNumericArray interface object length +PASS CSSNumericArray interface object name +PASS CSSNumericArray interface: existence and properties of interface prototype object +PASS CSSNumericArray interface: existence and properties of interface prototype object's "constructor" property +PASS CSSNumericArray interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSNumericArray interface: iterable<CSSNumericValue> +PASS CSSNumericArray interface: attribute length +PASS CSSTransformValue interface: existence and properties of interface object +PASS CSSTransformValue interface object length +PASS CSSTransformValue interface object name +PASS CSSTransformValue interface: existence and properties of interface prototype object +PASS CSSTransformValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSTransformValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSTransformValue interface: iterable<CSSTransformComponent> +PASS CSSTransformValue interface: attribute length +PASS CSSTransformValue interface: attribute is2D +PASS CSSTransformValue interface: operation toMatrix() +PASS CSSTransformValue must be primary interface of transformValue +PASS Stringification of transformValue +PASS CSSTransformValue interface: transformValue must inherit property "length" with the proper type +PASS CSSTransformValue interface: transformValue must inherit property "is2D" with the proper type +PASS CSSTransformValue interface: transformValue must inherit property "toMatrix()" with the proper type +PASS CSSStyleValue interface: transformValue must inherit property "parse(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parse(USVString, USVString) on transformValue with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parse" missing +PASS CSSStyleValue interface: transformValue must inherit property "parseAll(USVString, USVString)" with the proper type +FAIL CSSStyleValue interface: calling parseAll(USVString, USVString) on transformValue with too few arguments must throw TypeError assert_own_property: interface object must have static operation as own property expected property "parseAll" missing +PASS CSSTransformComponent interface: existence and properties of interface object +PASS CSSTransformComponent interface object length +PASS CSSTransformComponent interface object name +PASS CSSTransformComponent interface: existence and properties of interface prototype object +PASS CSSTransformComponent interface: existence and properties of interface prototype object's "constructor" property +PASS CSSTransformComponent interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSTransformComponent interface: stringifier +PASS CSSTransformComponent interface: attribute is2D +PASS CSSTransformComponent interface: operation toMatrix() +PASS CSSTranslate interface: existence and properties of interface object +PASS CSSTranslate interface object length +PASS CSSTranslate interface object name +PASS CSSTranslate interface: existence and properties of interface prototype object +PASS CSSTranslate interface: existence and properties of interface prototype object's "constructor" property +PASS CSSTranslate interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSTranslate interface: attribute x +PASS CSSTranslate interface: attribute y +PASS CSSTranslate interface: attribute z +PASS CSSTranslate must be primary interface of transformValue[0] +PASS Stringification of transformValue[0] +PASS CSSTranslate interface: transformValue[0] must inherit property "x" with the proper type +PASS CSSTranslate interface: transformValue[0] must inherit property "y" with the proper type +PASS CSSTranslate interface: transformValue[0] must inherit property "z" with the proper type +PASS CSSTransformComponent interface: transformValue[0] must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: transformValue[0] must inherit property "toMatrix()" with the proper type +PASS CSSRotate interface: existence and properties of interface object +PASS CSSRotate interface object length +PASS CSSRotate interface object name +PASS CSSRotate interface: existence and properties of interface prototype object +PASS CSSRotate interface: existence and properties of interface prototype object's "constructor" property +PASS CSSRotate interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSRotate interface: attribute x +PASS CSSRotate interface: attribute y +PASS CSSRotate interface: attribute z +PASS CSSRotate interface: attribute angle +PASS CSSRotate must be primary interface of rotate +PASS Stringification of rotate +PASS CSSRotate interface: rotate must inherit property "x" with the proper type +PASS CSSRotate interface: rotate must inherit property "y" with the proper type +PASS CSSRotate interface: rotate must inherit property "z" with the proper type +PASS CSSRotate interface: rotate must inherit property "angle" with the proper type +PASS CSSTransformComponent interface: rotate must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: rotate must inherit property "toMatrix()" with the proper type +PASS CSSScale interface: existence and properties of interface object +PASS CSSScale interface object length +PASS CSSScale interface object name +PASS CSSScale interface: existence and properties of interface prototype object +PASS CSSScale interface: existence and properties of interface prototype object's "constructor" property +PASS CSSScale interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSScale interface: attribute x +PASS CSSScale interface: attribute y +PASS CSSScale interface: attribute z +PASS CSSScale must be primary interface of scale +PASS Stringification of scale +PASS CSSScale interface: scale must inherit property "x" with the proper type +PASS CSSScale interface: scale must inherit property "y" with the proper type +PASS CSSScale interface: scale must inherit property "z" with the proper type +PASS CSSTransformComponent interface: scale must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: scale must inherit property "toMatrix()" with the proper type +PASS CSSSkew interface: existence and properties of interface object +PASS CSSSkew interface object length +PASS CSSSkew interface object name +PASS CSSSkew interface: existence and properties of interface prototype object +PASS CSSSkew interface: existence and properties of interface prototype object's "constructor" property +PASS CSSSkew interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSSkew interface: attribute ax +PASS CSSSkew interface: attribute ay +PASS CSSSkew must be primary interface of skew +PASS Stringification of skew +PASS CSSSkew interface: skew must inherit property "ax" with the proper type +PASS CSSSkew interface: skew must inherit property "ay" with the proper type +PASS CSSTransformComponent interface: skew must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: skew must inherit property "toMatrix()" with the proper type +PASS CSSSkewX interface: existence and properties of interface object +PASS CSSSkewX interface object length +PASS CSSSkewX interface object name +PASS CSSSkewX interface: existence and properties of interface prototype object +PASS CSSSkewX interface: existence and properties of interface prototype object's "constructor" property +PASS CSSSkewX interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSSkewX interface: attribute ax +PASS CSSSkewX must be primary interface of skewX +PASS Stringification of skewX +PASS CSSSkewX interface: skewX must inherit property "ax" with the proper type +PASS CSSTransformComponent interface: skewX must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: skewX must inherit property "toMatrix()" with the proper type +PASS CSSSkewY interface: existence and properties of interface object +PASS CSSSkewY interface object length +PASS CSSSkewY interface object name +PASS CSSSkewY interface: existence and properties of interface prototype object +PASS CSSSkewY interface: existence and properties of interface prototype object's "constructor" property +PASS CSSSkewY interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSSkewY interface: attribute ay +PASS CSSSkewY must be primary interface of skewY +PASS Stringification of skewY +PASS CSSSkewY interface: skewY must inherit property "ay" with the proper type +PASS CSSTransformComponent interface: skewY must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: skewY must inherit property "toMatrix()" with the proper type +PASS CSSPerspective interface: existence and properties of interface object +PASS CSSPerspective interface object length +PASS CSSPerspective interface object name +PASS CSSPerspective interface: existence and properties of interface prototype object +PASS CSSPerspective interface: existence and properties of interface prototype object's "constructor" property +PASS CSSPerspective interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSPerspective interface: attribute length +PASS CSSPerspective must be primary interface of perspective +PASS Stringification of perspective +PASS CSSPerspective interface: perspective must inherit property "length" with the proper type +PASS CSSTransformComponent interface: perspective must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: perspective must inherit property "toMatrix()" with the proper type +PASS CSSMatrixComponent interface: existence and properties of interface object +PASS CSSMatrixComponent interface object length +PASS CSSMatrixComponent interface object name +PASS CSSMatrixComponent interface: existence and properties of interface prototype object +PASS CSSMatrixComponent interface: existence and properties of interface prototype object's "constructor" property +PASS CSSMatrixComponent interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSMatrixComponent interface: attribute matrix +PASS CSSMatrixComponent must be primary interface of matrix +PASS Stringification of matrix +PASS CSSMatrixComponent interface: matrix must inherit property "matrix" with the proper type +PASS CSSTransformComponent interface: matrix must inherit property "is2D" with the proper type +PASS CSSTransformComponent interface: matrix must inherit property "toMatrix()" with the proper type +PASS CSSImageValue interface: existence and properties of interface object +PASS CSSImageValue interface object length +PASS CSSImageValue interface object name +PASS CSSImageValue interface: existence and properties of interface prototype object +PASS CSSImageValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSImageValue interface: existence and properties of interface prototype object's @@unscopables property +FAIL CSSColorValue interface: existence and properties of interface object assert_equals: prototype of CSSColorValue is not CSSStyleValue expected function "function CSSStyleValue() { [native code] }" but got function "function () { [native code] }" +PASS CSSColorValue interface object length +PASS CSSColorValue interface object name +FAIL CSSColorValue interface: existence and properties of interface prototype object assert_equals: prototype of CSSColorValue.prototype is not CSSStyleValue.prototype expected [stringifying object threw TypeError: Illegal invocation with type object] but got object "[object Object]" +PASS CSSColorValue interface: existence and properties of interface prototype object's "constructor" property +PASS CSSColorValue interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSColorValue interface: operation toRGB() +PASS CSSColorValue interface: operation toHSL() +FAIL CSSColorValue interface: operation toHWB() assert_own_property: interface prototype object missing non-static operation expected property "toHWB" missing +FAIL CSSColorValue interface: operation toGray() assert_own_property: interface prototype object missing non-static operation expected property "toGray" missing +FAIL CSSColorValue interface: operation toLCH() assert_own_property: interface prototype object missing non-static operation expected property "toLCH" missing +FAIL CSSColorValue interface: operation toLab() assert_own_property: interface prototype object missing non-static operation expected property "toLab" missing +FAIL CSSColorValue interface: operation toColor(CSSKeywordish) assert_own_property: interface prototype object missing non-static operation expected property "toColor" missing +FAIL CSSColorValue interface: operation parse(USVString) assert_own_property: interface object missing static operation expected property "parse" missing +PASS CSSRGB interface: existence and properties of interface object +PASS CSSRGB interface object length +PASS CSSRGB interface object name +PASS CSSRGB interface: existence and properties of interface prototype object +PASS CSSRGB interface: existence and properties of interface prototype object's "constructor" property +PASS CSSRGB interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSRGB interface: attribute r +PASS CSSRGB interface: attribute g +PASS CSSRGB interface: attribute b +PASS CSSRGB interface: attribute alpha +PASS CSSHSL interface: existence and properties of interface object +PASS CSSHSL interface object length +PASS CSSHSL interface object name +PASS CSSHSL interface: existence and properties of interface prototype object +PASS CSSHSL interface: existence and properties of interface prototype object's "constructor" property +PASS CSSHSL interface: existence and properties of interface prototype object's @@unscopables property +PASS CSSHSL interface: attribute h +PASS CSSHSL interface: attribute s +PASS CSSHSL interface: attribute l +PASS CSSHSL interface: attribute alpha +FAIL CSSHWB interface: existence and properties of interface object assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface object length assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface object name assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: attribute h assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: attribute w assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: attribute b assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSHWB interface: attribute alpha assert_own_property: self does not have own property "CSSHWB" expected property "CSSHWB" missing +FAIL CSSGray interface: existence and properties of interface object assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface object length assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface object name assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface: attribute gray assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSGray interface: attribute alpha assert_own_property: self does not have own property "CSSGray" expected property "CSSGray" missing +FAIL CSSLCH interface: existence and properties of interface object assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface object length assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface object name assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: attribute l assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: attribute c assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: attribute h assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLCH interface: attribute alpha assert_own_property: self does not have own property "CSSLCH" expected property "CSSLCH" missing +FAIL CSSLab interface: existence and properties of interface object assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface object length assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface object name assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: attribute l assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: attribute a assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: attribute b assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSLab interface: attribute alpha assert_own_property: self does not have own property "CSSLab" expected property "CSSLab" missing +FAIL CSSColor interface: existence and properties of interface object assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSColor interface object length assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSColor interface object name assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSColor interface: existence and properties of interface prototype object assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSColor interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +FAIL CSSColor interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "CSSColor" expected property "CSSColor" missing +PASS CSSStyleRule interface: attribute styleMap +PASS CSS namespace: operation escape(CSSOMString) +PASS CSS namespace: operation number(double) +PASS CSS namespace: operation percent(double) +PASS CSS namespace: operation em(double) +PASS CSS namespace: operation ex(double) +PASS CSS namespace: operation ch(double) +FAIL CSS namespace: operation ic(double) assert_own_property: namespace object missing operation "ic" expected property "ic" missing +PASS CSS namespace: operation rem(double) +FAIL CSS namespace: operation lh(double) assert_own_property: namespace object missing operation "lh" expected property "lh" missing +FAIL CSS namespace: operation rlh(double) assert_own_property: namespace object missing operation "rlh" expected property "rlh" missing +PASS CSS namespace: operation vw(double) +PASS CSS namespace: operation vh(double) +FAIL CSS namespace: operation vi(double) assert_own_property: namespace object missing operation "vi" expected property "vi" missing +FAIL CSS namespace: operation vb(double) assert_own_property: namespace object missing operation "vb" expected property "vb" missing +PASS CSS namespace: operation vmin(double) +PASS CSS namespace: operation vmax(double) +PASS CSS namespace: operation cm(double) +PASS CSS namespace: operation mm(double) +PASS CSS namespace: operation Q(double) +PASS CSS namespace: operation in(double) +PASS CSS namespace: operation pt(double) +PASS CSS namespace: operation pc(double) +PASS CSS namespace: operation px(double) +PASS CSS namespace: operation deg(double) +PASS CSS namespace: operation grad(double) +PASS CSS namespace: operation rad(double) +PASS CSS namespace: operation turn(double) +PASS CSS namespace: operation s(double) +PASS CSS namespace: operation ms(double) +PASS CSS namespace: operation Hz(double) +PASS CSS namespace: operation kHz(double) +PASS CSS namespace: operation dpi(double) +PASS CSS namespace: operation dpcm(double) +PASS CSS namespace: operation dppx(double) +PASS CSS namespace: operation fr(double) +FAIL SVGElement interface: attribute attributeStyleMap assert_own_property: expected property "attributeStyleMap" missing +FAIL HTMLElement interface: attribute attributeStyleMap assert_own_property: expected property "attributeStyleMap" missing +PASS Element interface: operation computedStyleMap() +FAIL MathMLElement interface: attribute attributeStyleMap assert_own_property: expected property "attributeStyleMap" missing +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt new file mode 100644 index 0000000..0c26f729 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt
@@ -0,0 +1,118 @@ +This is a testharness.js-based test. +Found 114 tests; 71 PASS, 43 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface ServiceWorkerRegistration: original interface defined +PASS Partial interface ServiceWorkerRegistration: member names are unique +PASS Partial interface ServiceWorkerGlobalScope: original interface defined +PASS Partial interface ServiceWorkerGlobalScope: member names are unique +PASS Partial interface ServiceWorkerGlobalScope[2]: original interface defined +PASS Partial interface ServiceWorkerGlobalScope[2]: member names are unique +PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique +FAIL PaymentManager interface: existence and properties of interface object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object length assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object name assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager must be primary interface of paymentManager assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +PASS Stringification of paymentManager +PASS PaymentManager interface: paymentManager must inherit property "instruments" with the proper type +PASS PaymentManager interface: paymentManager must inherit property "userHint" with the proper type +PASS PaymentManager interface: paymentManager must inherit property "enableDelegations(sequence<PaymentDelegation>)" with the proper type +PASS PaymentManager interface: calling enableDelegations(sequence<PaymentDelegation>) on paymentManager with too few arguments must throw TypeError +PASS PaymentInstruments interface: existence and properties of interface object +PASS PaymentInstruments interface object length +PASS PaymentInstruments interface object name +PASS PaymentInstruments interface: existence and properties of interface prototype object +PASS PaymentInstruments interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentInstruments interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentInstruments interface: operation delete(DOMString) +PASS PaymentInstruments interface: operation get(DOMString) +PASS PaymentInstruments interface: operation keys() +PASS PaymentInstruments interface: operation has(DOMString) +PASS PaymentInstruments interface: operation set(DOMString, PaymentInstrument) +PASS PaymentInstruments interface: operation clear() +PASS PaymentInstruments must be primary interface of instruments +PASS Stringification of instruments +PASS PaymentInstruments interface: instruments must inherit property "delete(DOMString)" with the proper type +PASS PaymentInstruments interface: calling delete(DOMString) on instruments with too few arguments must throw TypeError +PASS PaymentInstruments interface: instruments must inherit property "get(DOMString)" with the proper type +PASS PaymentInstruments interface: calling get(DOMString) on instruments with too few arguments must throw TypeError +PASS PaymentInstruments interface: instruments must inherit property "keys()" with the proper type +PASS PaymentInstruments interface: instruments must inherit property "has(DOMString)" with the proper type +PASS PaymentInstruments interface: calling has(DOMString) on instruments with too few arguments must throw TypeError +PASS PaymentInstruments interface: instruments must inherit property "set(DOMString, PaymentInstrument)" with the proper type +PASS PaymentInstruments interface: calling set(DOMString, PaymentInstrument) on instruments with too few arguments must throw TypeError +PASS PaymentInstruments interface: instruments must inherit property "clear()" with the proper type +PASS CanMakePaymentEvent interface: existence and properties of interface object +FAIL CanMakePaymentEvent interface object length assert_equals: wrong value for CanMakePaymentEvent.length expected 1 but got 2 +PASS CanMakePaymentEvent interface object name +PASS CanMakePaymentEvent interface: existence and properties of interface prototype object +PASS CanMakePaymentEvent interface: existence and properties of interface prototype object's "constructor" property +PASS CanMakePaymentEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS CanMakePaymentEvent interface: attribute topOrigin +PASS CanMakePaymentEvent interface: attribute paymentRequestOrigin +PASS CanMakePaymentEvent interface: attribute methodData +PASS CanMakePaymentEvent interface: operation respondWith(Promise<boolean>) +FAIL CanMakePaymentEvent must be primary interface of new CanMakePaymentEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL Stringification of new CanMakePaymentEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "topOrigin" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "paymentRequestOrigin" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "methodData" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "respondWith(Promise<boolean>)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +FAIL CanMakePaymentEvent interface: calling respondWith(Promise<boolean>) on new CanMakePaymentEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'CanMakePaymentEvent': 2 arguments required, but only 1 present." +PASS PaymentRequestEvent interface: existence and properties of interface object +FAIL PaymentRequestEvent interface object length assert_equals: wrong value for PaymentRequestEvent.length expected 1 but got 2 +PASS PaymentRequestEvent interface object name +PASS PaymentRequestEvent interface: existence and properties of interface prototype object +PASS PaymentRequestEvent interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentRequestEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentRequestEvent interface: attribute topOrigin +PASS PaymentRequestEvent interface: attribute paymentRequestOrigin +PASS PaymentRequestEvent interface: attribute paymentRequestId +PASS PaymentRequestEvent interface: attribute methodData +PASS PaymentRequestEvent interface: attribute total +PASS PaymentRequestEvent interface: attribute modifiers +PASS PaymentRequestEvent interface: attribute instrumentKey +FAIL PaymentRequestEvent interface: attribute requestBillingAddress assert_true: The prototype object must have a property "requestBillingAddress" expected true got false +PASS PaymentRequestEvent interface: attribute paymentOptions +PASS PaymentRequestEvent interface: attribute shippingOptions +PASS PaymentRequestEvent interface: operation openWindow(USVString) +PASS PaymentRequestEvent interface: operation changePaymentMethod(DOMString, optional object?) +FAIL PaymentRequestEvent interface: operation changeShippingAddress(optional AddressInit) assert_equals: property has wrong .length expected 0 but got 1 +PASS PaymentRequestEvent interface: operation changeShippingOption(DOMString) +PASS PaymentRequestEvent interface: operation respondWith(Promise<PaymentHandlerResponse>) +FAIL PaymentRequestEvent must be primary interface of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL Stringification of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "topOrigin" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentRequestOrigin" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentRequestId" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "methodData" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "total" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "modifiers" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "instrumentKey" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "requestBillingAddress" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentOptions" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "shippingOptions" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "openWindow(USVString)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: calling openWindow(USVString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changePaymentMethod(DOMString, optional object?)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: calling changePaymentMethod(DOMString, optional object?) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingAddress(optional AddressInit)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: calling changeShippingAddress(optional AddressInit) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingOption(DOMString)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: calling changeShippingOption(DOMString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "respondWith(Promise<PaymentHandlerResponse>)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +FAIL PaymentRequestEvent interface: calling respondWith(Promise<PaymentHandlerResponse>) on new PaymentRequestEvent("type") with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." +PASS ServiceWorkerRegistration interface: attribute paymentManager +PASS ServiceWorkerRegistration interface: registration must inherit property "paymentManager" with the proper type +PASS ServiceWorkerGlobalScope interface: attribute oncanmakepayment +PASS ServiceWorkerGlobalScope interface: attribute onpaymentrequest +PASS ServiceWorkerGlobalScope interface: self must inherit property "oncanmakepayment" with the proper type +PASS ServiceWorkerGlobalScope interface: self must inherit property "onpaymentrequest" with the proper type +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt new file mode 100644 index 0000000..2ee5817 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.sharedworker-expected.txt
@@ -0,0 +1,36 @@ +This is a testharness.js-based test. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface ServiceWorkerRegistration: original interface defined +PASS Partial interface ServiceWorkerRegistration: member names are unique +PASS Partial interface ServiceWorkerGlobalScope: original interface defined +PASS Partial interface ServiceWorkerGlobalScope: member names are unique +PASS Partial interface ServiceWorkerGlobalScope[2]: original interface defined +PASS Partial interface ServiceWorkerGlobalScope[2]: member names are unique +PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique +FAIL PaymentManager interface: existence and properties of interface object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object length assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object name assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +PASS PaymentInstruments interface: existence and properties of interface object +PASS PaymentInstruments interface object length +PASS PaymentInstruments interface object name +PASS PaymentInstruments interface: existence and properties of interface prototype object +PASS PaymentInstruments interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentInstruments interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentInstruments interface: operation delete(DOMString) +PASS PaymentInstruments interface: operation get(DOMString) +PASS PaymentInstruments interface: operation keys() +PASS PaymentInstruments interface: operation has(DOMString) +PASS PaymentInstruments interface: operation set(DOMString, PaymentInstrument) +PASS PaymentInstruments interface: operation clear() +PASS CanMakePaymentEvent interface: existence and properties of interface object +PASS PaymentRequestEvent interface: existence and properties of interface object +PASS ServiceWorkerRegistration interface: attribute paymentManager +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt new file mode 100644 index 0000000..2ee5817 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-handler/idlharness.https.any.worker-expected.txt
@@ -0,0 +1,36 @@ +This is a testharness.js-based test. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface ServiceWorkerRegistration: original interface defined +PASS Partial interface ServiceWorkerRegistration: member names are unique +PASS Partial interface ServiceWorkerGlobalScope: original interface defined +PASS Partial interface ServiceWorkerGlobalScope: member names are unique +PASS Partial interface ServiceWorkerGlobalScope[2]: original interface defined +PASS Partial interface ServiceWorkerGlobalScope[2]: member names are unique +PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique +FAIL PaymentManager interface: existence and properties of interface object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object length assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface object name assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute instruments assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: attribute userHint assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +FAIL PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>) assert_own_property: self does not have own property "PaymentManager" expected property "PaymentManager" missing +PASS PaymentInstruments interface: existence and properties of interface object +PASS PaymentInstruments interface object length +PASS PaymentInstruments interface object name +PASS PaymentInstruments interface: existence and properties of interface prototype object +PASS PaymentInstruments interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentInstruments interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentInstruments interface: operation delete(DOMString) +PASS PaymentInstruments interface: operation get(DOMString) +PASS PaymentInstruments interface: operation keys() +PASS PaymentInstruments interface: operation has(DOMString) +PASS PaymentInstruments interface: operation set(DOMString, PaymentInstrument) +PASS PaymentInstruments interface: operation clear() +PASS CanMakePaymentEvent interface: existence and properties of interface object +PASS PaymentRequestEvent interface: existence and properties of interface object +PASS ServiceWorkerRegistration interface: attribute paymentManager +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-request/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-request/idlharness.https.window-expected.txt new file mode 100644 index 0000000..dd488a1 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/payment-request/idlharness.https.window-expected.txt
@@ -0,0 +1,95 @@ +This is a testharness.js-based test. +Found 91 tests; 90 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS idl_test setup +PASS idl_test validation +PASS PaymentRequest interface: existence and properties of interface object +FAIL PaymentRequest interface object length assert_equals: wrong value for PaymentRequest.length expected 2 but got 1 +PASS PaymentRequest interface object name +PASS PaymentRequest interface: existence and properties of interface prototype object +PASS PaymentRequest interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentRequest interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentRequest interface: operation show(optional Promise<PaymentDetailsUpdate>) +PASS PaymentRequest interface: operation abort() +PASS PaymentRequest interface: operation canMakePayment() +PASS PaymentRequest interface: attribute id +PASS PaymentRequest interface: attribute shippingAddress +PASS PaymentRequest interface: attribute shippingOption +PASS PaymentRequest interface: attribute shippingType +PASS PaymentRequest interface: attribute onshippingaddresschange +PASS PaymentRequest interface: attribute onshippingoptionchange +PASS PaymentRequest interface: attribute onpaymentmethodchange +PASS PaymentRequest must be primary interface of paymentRequest +PASS Stringification of paymentRequest +PASS PaymentRequest interface: paymentRequest must inherit property "show(optional Promise<PaymentDetailsUpdate>)" with the proper type +PASS PaymentRequest interface: calling show(optional Promise<PaymentDetailsUpdate>) on paymentRequest with too few arguments must throw TypeError +PASS PaymentRequest interface: paymentRequest must inherit property "abort()" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "canMakePayment()" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "id" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "shippingAddress" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "shippingOption" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "shippingType" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "onshippingaddresschange" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "onshippingoptionchange" with the proper type +PASS PaymentRequest interface: paymentRequest must inherit property "onpaymentmethodchange" with the proper type +PASS PaymentAddress interface: existence and properties of interface object +PASS PaymentAddress interface object length +PASS PaymentAddress interface object name +PASS PaymentAddress interface: existence and properties of interface prototype object +PASS PaymentAddress interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentAddress interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentAddress interface: operation toJSON() +PASS PaymentAddress interface: attribute city +PASS PaymentAddress interface: attribute country +PASS PaymentAddress interface: attribute dependentLocality +PASS PaymentAddress interface: attribute organization +PASS PaymentAddress interface: attribute phone +PASS PaymentAddress interface: attribute postalCode +PASS PaymentAddress interface: attribute recipient +PASS PaymentAddress interface: attribute region +PASS PaymentAddress interface: attribute sortingCode +PASS PaymentAddress interface: attribute addressLine +PASS PaymentResponse interface: existence and properties of interface object +PASS PaymentResponse interface object length +PASS PaymentResponse interface object name +PASS PaymentResponse interface: existence and properties of interface prototype object +PASS PaymentResponse interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentResponse interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentResponse interface: operation toJSON() +PASS PaymentResponse interface: attribute requestId +PASS PaymentResponse interface: attribute methodName +PASS PaymentResponse interface: attribute details +PASS PaymentResponse interface: attribute shippingAddress +PASS PaymentResponse interface: attribute shippingOption +PASS PaymentResponse interface: attribute payerName +PASS PaymentResponse interface: attribute payerEmail +PASS PaymentResponse interface: attribute payerPhone +PASS PaymentResponse interface: operation complete(optional PaymentComplete) +PASS PaymentResponse interface: operation retry(optional PaymentValidationErrors) +PASS PaymentResponse interface: attribute onpayerdetailchange +PASS PaymentMethodChangeEvent interface: existence and properties of interface object +PASS PaymentMethodChangeEvent interface object length +PASS PaymentMethodChangeEvent interface object name +PASS PaymentMethodChangeEvent interface: existence and properties of interface prototype object +PASS PaymentMethodChangeEvent interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentMethodChangeEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentMethodChangeEvent interface: attribute methodName +PASS PaymentMethodChangeEvent interface: attribute methodDetails +PASS PaymentMethodChangeEvent must be primary interface of new PaymentMethodChangeEvent("paymentmethodchange") +PASS Stringification of new PaymentMethodChangeEvent("paymentmethodchange") +PASS PaymentMethodChangeEvent interface: new PaymentMethodChangeEvent("paymentmethodchange") must inherit property "methodName" with the proper type +PASS PaymentMethodChangeEvent interface: new PaymentMethodChangeEvent("paymentmethodchange") must inherit property "methodDetails" with the proper type +PASS PaymentRequestUpdateEvent interface: new PaymentMethodChangeEvent("paymentmethodchange") must inherit property "updateWith(Promise<PaymentDetailsUpdate>)" with the proper type +PASS PaymentRequestUpdateEvent interface: calling updateWith(Promise<PaymentDetailsUpdate>) on new PaymentMethodChangeEvent("paymentmethodchange") with too few arguments must throw TypeError +PASS PaymentRequestUpdateEvent interface: existence and properties of interface object +PASS PaymentRequestUpdateEvent interface object length +PASS PaymentRequestUpdateEvent interface object name +PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object +PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object's "constructor" property +PASS PaymentRequestUpdateEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS PaymentRequestUpdateEvent interface: operation updateWith(Promise<PaymentDetailsUpdate>) +PASS PaymentRequestUpdateEvent must be primary interface of new PaymentRequestUpdateEvent("paymentrequestupdate") +PASS Stringification of new PaymentRequestUpdateEvent("paymentrequestupdate") +PASS PaymentRequestUpdateEvent interface: new PaymentRequestUpdateEvent("paymentrequestupdate") must inherit property "updateWith(Promise<PaymentDetailsUpdate>)" with the proper type +PASS PaymentRequestUpdateEvent interface: calling updateWith(Promise<PaymentDetailsUpdate>) on new PaymentRequestUpdateEvent("paymentrequestupdate") with too few arguments must throw TypeError +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters-a-area.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters-a-area.window-expected.txt new file mode 100644 index 0000000..21d9d9d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters-a-area.window-expected.txt
@@ -0,0 +1,431 @@ +This is a testharness.js-based test. +Found 413 tests; 253 PASS, 160 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Loading data… +PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. +PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. +PASS <a>: Setting <a://example.net>.protocol = 'b' +PASS <area>: Setting <a://example.net>.protocol = 'b' +PASS <a>: Setting <javascript:alert(1)>.protocol = 'defuse' +PASS <area>: Setting <javascript:alert(1)>.protocol = 'defuse' +PASS <a>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased +PASS <area>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased +PASS <a>: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected +PASS <area>: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected +PASS <a>: Setting <a://example.net>.protocol = '0b' No leading digit +PASS <area>: Setting <a://example.net>.protocol = '0b' No leading digit +PASS <a>: Setting <a://example.net>.protocol = '+b' No leading punctuation +PASS <area>: Setting <a://example.net>.protocol = '+b' No leading punctuation +PASS <a>: Setting <a://example.net>.protocol = 'bC0+-.' +PASS <area>: Setting <a://example.net>.protocol = 'bC0+-.' +PASS <a>: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable +PASS <area>: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable +PASS <a>: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected +PASS <area>: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected +PASS <a>: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file +PASS <area>: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file +PASS <a>: Setting <https://example.net:1234>.protocol = 'file' +PASS <area>: Setting <https://example.net:1234>.protocol = 'file' +PASS <a>: Setting <wss://x:x@example.net:1234>.protocol = 'file' +PASS <area>: Setting <wss://x:x@example.net:1234>.protocol = 'file' +FAIL <a>: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host assert_equals: expected "file:///" but got "http://localhost/" +FAIL <area>: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host assert_equals: expected "file:///" but got "http://localhost/" +PASS <a>: Setting <file:///test>.protocol = 'https' +PASS <area>: Setting <file:///test>.protocol = 'https' +PASS <a>: Setting <file:>.protocol = 'wss' +PASS <area>: Setting <file:>.protocol = 'wss' +FAIL <a>: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special assert_equals: expected "http://example.net/" but got "b://example.net/" +FAIL <area>: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special assert_equals: expected "http://example.net/" but got "b://example.net/" +FAIL <a>: Setting <file://hi/path>.protocol = 's' assert_equals: expected "file://hi/path" but got "s://hi/path" +FAIL <area>: Setting <file://hi/path>.protocol = 's' assert_equals: expected "file://hi/path" but got "s://hi/path" +FAIL <a>: Setting <https://example.net>.protocol = 's' assert_equals: expected "https://example.net/" but got "s://example.net/" +FAIL <area>: Setting <https://example.net>.protocol = 's' assert_equals: expected "https://example.net/" but got "s://example.net/" +FAIL <a>: Setting <ftp://example.net>.protocol = 'test' assert_equals: expected "ftp://example.net/" but got "test://example.net/" +FAIL <area>: Setting <ftp://example.net>.protocol = 'test' assert_equals: expected "ftp://example.net/" but got "test://example.net/" +FAIL <a>: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must. assert_equals: expected "mailto:me@example.net" but got "http://me@example.net/" +FAIL <area>: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must. assert_equals: expected "mailto:me@example.net" but got "http://me@example.net/" +FAIL <a>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/" +FAIL <area>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/" +FAIL <a>: Setting <ssh://me@example.net>.protocol = 'https' assert_equals: expected "ssh://me@example.net" but got "https://me@example.net/" +FAIL <area>: Setting <ssh://me@example.net>.protocol = 'https' assert_equals: expected "ssh://me@example.net" but got "https://me@example.net/" +FAIL <a>: Setting <ssh://me@example.net>.protocol = 'file' assert_equals: expected "ssh://me@example.net" but got "file://me%40example.net/" +FAIL <area>: Setting <ssh://me@example.net>.protocol = 'file' assert_equals: expected "ssh://me@example.net" but got "file://me%40example.net/" +FAIL <a>: Setting <ssh://example.net>.protocol = 'file' assert_equals: expected "ssh://example.net" but got "file://example.net/" +FAIL <area>: Setting <ssh://example.net>.protocol = 'file' assert_equals: expected "ssh://example.net" but got "file://example.net/" +FAIL <a>: Setting <nonsense:///test>.protocol = 'https' assert_equals: expected "nonsense:///test" but got "https://test/" +FAIL <area>: Setting <nonsense:///test>.protocol = 'https' assert_equals: expected "nonsense:///test" but got "https://test/" +PASS <a>: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored +PASS <area>: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored +PASS <a>: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored +PASS <area>: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored +PASS <a>: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme. +PASS <area>: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme. +PASS <a>: Setting <file:///home/you/index.html>.username = 'me' No host means no username +PASS <area>: Setting <file:///home/you/index.html>.username = 'me' No host means no username +PASS <a>: Setting <unix:/run/foo.socket>.username = 'me' No host means no username +PASS <area>: Setting <unix:/run/foo.socket>.username = 'me' No host means no username +PASS <a>: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username +PASS <area>: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username +PASS <a>: Setting <javascript:alert(1)>.username = 'wario' +PASS <area>: Setting <javascript:alert(1)>.username = 'wario' +PASS <a>: Setting <http://example.net>.username = 'me' +PASS <area>: Setting <http://example.net>.username = 'me' +PASS <a>: Setting <http://:secret@example.net>.username = 'me' +PASS <area>: Setting <http://:secret@example.net>.username = 'me' +PASS <a>: Setting <http://me@example.net>.username = '' +PASS <area>: Setting <http://me@example.net>.username = '' +PASS <a>: Setting <http://me:secret@example.net>.username = '' +PASS <area>: Setting <http://me:secret@example.net>.username = '' +FAIL <a>: Setting <http://example.net>.username = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +FAIL <area>: Setting <http://example.net>.username = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS <a>: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS <area>: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS <a>: Setting <sc:///>.username = 'x' +PASS <area>: Setting <sc:///>.username = 'x' +FAIL <a>: Setting <javascript://x/>.username = 'wario' assert_equals: expected "javascript://wario@x/" but got "javascript://x/" +FAIL <area>: Setting <javascript://x/>.username = 'wario' assert_equals: expected "javascript://wario@x/" but got "javascript://x/" +PASS <a>: Setting <file://test/>.username = 'test' +PASS <area>: Setting <file://test/>.username = 'test' +PASS <a>: Setting <file:///home/me/index.html>.password = 'secret' No host means no password +PASS <area>: Setting <file:///home/me/index.html>.password = 'secret' No host means no password +PASS <a>: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password +PASS <area>: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password +PASS <a>: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password +PASS <area>: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password +PASS <a>: Setting <http://example.net>.password = 'secret' +PASS <area>: Setting <http://example.net>.password = 'secret' +PASS <a>: Setting <http://me@example.net>.password = 'secret' +PASS <area>: Setting <http://me@example.net>.password = 'secret' +PASS <a>: Setting <http://:secret@example.net>.password = '' +PASS <area>: Setting <http://:secret@example.net>.password = '' +PASS <a>: Setting <http://me:secret@example.net>.password = '' +PASS <area>: Setting <http://me:secret@example.net>.password = '' +FAIL <a>: Setting <http://example.net>.password = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +FAIL <area>: Setting <http://example.net>.password = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS <a>: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS <area>: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS <a>: Setting <sc:///>.password = 'x' +PASS <area>: Setting <sc:///>.password = 'x' +FAIL <a>: Setting <javascript://x/>.password = 'bowser' assert_equals: expected "javascript://:bowser@x/" but got "javascript://x/" +FAIL <area>: Setting <javascript://x/>.password = 'bowser' assert_equals: expected "javascript://:bowser@x/" but got "javascript://x/" +PASS <a>: Setting <file://test/>.password = 'test' +PASS <area>: Setting <file://test/>.password = 'test' +FAIL <a>: Setting <sc://x/>.host = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.host = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL <a>: Setting <sc://x/>.host = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = ' ' assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.host = ' ' assert_equals: expected "x" but got "" +FAIL <a>: Setting <sc://x/>.host = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.host = '@' assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.host = '@' assert_equals: expected "x" but got "" +FAIL <a>: Setting <sc://x/>.host = 'ß' assert_equals: expected "sc://%C3%9F/" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.host = 'ß' assert_equals: expected "sc://%C3%9F/" but got "sc://x/" +FAIL <a>: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing assert_equals: expected "https://xn--zca/" but got "https://ss/" +FAIL <area>: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing assert_equals: expected "https://xn--zca/" but got "https://ss/" +PASS <a>: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host +PASS <area>: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host +PASS <a>: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host +PASS <area>: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host +PASS <a>: Setting <http://example.net>.host = 'example.com:8080' +PASS <area>: Setting <http://example.net>.host = 'example.com:8080' +PASS <a>: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value +PASS <area>: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value +PASS <a>: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified +PASS <area>: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified +PASS <a>: Setting <http://example.net>.host = '' The empty host is not valid for special schemes +PASS <area>: Setting <http://example.net>.host = '' The empty host is not valid for special schemes +FAIL <a>: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL <area>: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL <a>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +FAIL <area>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS <a>: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized +PASS <area>: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized +PASS <a>: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized +PASS <area>: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized +PASS <a>: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416 +PASS <area>: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416 +PASS <a>: Setting <http://example.net>.host = 'example.com:80' Default port number is removed +PASS <area>: Setting <http://example.net>.host = 'example.com:80' Default port number is removed +PASS <a>: Setting <https://example.net>.host = 'example.com:443' Default port number is removed +PASS <area>: Setting <https://example.net>.host = 'example.com:443' Default port number is removed +PASS <a>: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme +PASS <area>: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme +PASS <a>: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port +PASS <area>: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port +PASS <a>: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored +PASS <a>: Setting <http://example.net/path>.host = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS <area>: Setting <http://example.net/path>.host = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL <a>: Setting <view-source+http://example.net/path>.host = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +FAIL <area>: Setting <view-source+http://example.net/path>.host = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +FAIL <a>: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.com:8080/path" but got "view-source+http://example.net/path" +FAIL <area>: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.com:8080/path" but got "view-source+http://example.net/path" +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <a>: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <area>: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <a>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers +PASS <area>: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers +PASS <a>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. +PASS <area>: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. +PASS <a>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 +PASS <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 +PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.4x]' +PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.4x]' +FAIL <a>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL <area>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL <a>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL <area>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL <a>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +FAIL <area>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +FAIL <a>: Setting <file://y/>.host = 'x:123' assert_equals: expected "file://y/" but got "file://x/" +FAIL <area>: Setting <file://y/>.host = 'x:123' assert_equals: expected "file://y/" but got "file://x/" +FAIL <a>: Setting <file://y/>.host = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL <area>: Setting <file://y/>.host = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL <a>: Setting <file://hi/x>.host = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL <area>: Setting <file://hi/x>.host = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL <a>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got "" +FAIL <area>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got "" +FAIL <a>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got "" +FAIL <area>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got "" +FAIL <a>: Setting <sc://x/>.hostname = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.hostname = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL <a>: Setting <sc://x/>.hostname = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = ' ' assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.hostname = ' ' assert_equals: expected "x" but got "" +FAIL <a>: Setting <sc://x/>.hostname = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.hostname = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL <a>: Setting <sc://x/>.hostname = '@' assert_equals: expected "x" but got "" +FAIL <area>: Setting <sc://x/>.hostname = '@' assert_equals: expected "x" but got "" +PASS <a>: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host +PASS <area>: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host +PASS <a>: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host +PASS <area>: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host +PASS <a>: Setting <http://example.net:8080>.hostname = 'example.com' +PASS <area>: Setting <http://example.net:8080>.hostname = 'example.com' +PASS <a>: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes +PASS <area>: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes +FAIL <a>: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL <area>: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL <a>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +FAIL <area>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS <a>: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized +PASS <area>: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized +PASS <a>: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized +PASS <area>: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized +PASS <a>: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value +PASS <area>: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value +PASS <a>: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value +PASS <area>: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value +PASS <a>: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS <area>: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS <a>: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS <area>: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS <a>: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS <area>: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS <a>: Setting <http://example.net/path>.hostname = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS <area>: Setting <http://example.net/path>.hostname = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL <a>: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +FAIL <area>: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +PASS <a>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6 +PASS <area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6 +PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]' +PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]' +FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL <a>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +FAIL <area>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +PASS <a>: Setting <file://y/>.hostname = 'x:123' +PASS <area>: Setting <file://y/>.hostname = 'x:123' +FAIL <a>: Setting <file://y/>.hostname = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL <area>: Setting <file://y/>.hostname = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL <a>: Setting <file://hi/x>.hostname = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL <area>: Setting <file://hi/x>.hostname = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL <a>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got "" +FAIL <area>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got "" +FAIL <a>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got "" +FAIL <area>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got "" +FAIL <a>: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p" +FAIL <area>: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p" +FAIL <a>: Setting <non-spec:/.//p>.hostname = '' assert_equals: expected "non-spec:////p" but got "non-spec:/.//p" +FAIL <area>: Setting <non-spec:/.//p>.hostname = '' assert_equals: expected "non-spec:////p" but got "non-spec:/.//p" +PASS <a>: Setting <http://example.net>.port = '8080' +PASS <area>: Setting <http://example.net>.port = '8080' +PASS <a>: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value +PASS <area>: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value +PASS <a>: Setting <http://example.net:8080>.port = '80' Default port number is removed +PASS <area>: Setting <http://example.net:8080>.port = '80' Default port number is removed +PASS <a>: Setting <https://example.net:4433>.port = '443' Default port number is removed +PASS <area>: Setting <https://example.net:4433>.port = '443' Default port number is removed +PASS <a>: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme +PASS <area>: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme +PASS <a>: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored +PASS <area>: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored +PASS <a>: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored +PASS <area>: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored +PASS <a>: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored +PASS <area>: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored +PASS <a>: Setting <http://example.net/path>.port = '8080\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS <area>: Setting <http://example.net/path>.port = '8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL <a>: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.net:8080/path" but got "view-source+http://example.net/path" +FAIL <area>: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.net:8080/path" but got "view-source+http://example.net/path" +PASS <a>: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <area>: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <a>: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <area>: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS <a>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers +PASS <area>: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers +FAIL <a>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path" +FAIL <area>: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path" +FAIL <a>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "example.net:8080" but got "" +FAIL <area>: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "example.net:8080" but got "" +PASS <a>: Setting <file://test/>.port = '12' +PASS <area>: Setting <file://test/>.port = '12' +FAIL <a>: Setting <file://localhost/>.port = '12' assert_equals: expected "file:///" but got "file://localhost/" +FAIL <area>: Setting <file://localhost/>.port = '12' assert_equals: expected "file:///" but got "file://localhost/" +PASS <a>: Setting <non-base:value>.port = '12' +PASS <area>: Setting <non-base:value>.port = '12' +PASS <a>: Setting <sc:///>.port = '12' +PASS <area>: Setting <sc:///>.port = '12' +FAIL <a>: Setting <sc://x/>.port = '12' assert_equals: expected "sc://x:12/" but got "sc://x/" +FAIL <area>: Setting <sc://x/>.port = '12' assert_equals: expected "sc://x:12/" but got "sc://x/" +FAIL <a>: Setting <javascript://x/>.port = '12' assert_equals: expected "javascript://x:12/" but got "javascript://x/" +FAIL <area>: Setting <javascript://x/>.port = '12' assert_equals: expected "javascript://x:12/" but got "javascript://x/" +PASS <a>: Setting <mailto:me@example.net>.pathname = '/foo' Cannot-be-a-base don’t have a path +PASS <area>: Setting <mailto:me@example.net>.pathname = '/foo' Cannot-be-a-base don’t have a path +FAIL <a>: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket' assert_equals: expected "unix:/var/run/bar.socket?timeout=10" but got "unix:/run/foo.socket?timeout=10" +FAIL <area>: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket' assert_equals: expected "unix:/var/run/bar.socket?timeout=10" but got "unix:/run/foo.socket?timeout=10" +PASS <a>: Setting <https://example.net#nav>.pathname = 'home' +PASS <area>: Setting <https://example.net#nav>.pathname = 'home' +PASS <a>: Setting <https://example.net#nav>.pathname = '../home' +PASS <area>: Setting <https://example.net#nav>.pathname = '../home' +PASS <a>: Setting <http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is a segment delimiter for 'special' URLs +PASS <area>: Setting <http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is a segment delimiter for 'special' URLs +FAIL <a>: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is *not* a segment delimiter for non-'special' URLs assert_equals: expected "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav" but got "view-source+http://example.net/home?lang=fr#nav" +FAIL <area>: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is *not* a segment delimiter for non-'special' URLs assert_equals: expected "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav" but got "view-source+http://example.net/home?lang=fr#nav" +FAIL <a>: Setting <a:/>.pathname = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. assert_equals: expected "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/" +FAIL <area>: Setting <a:/>.pathname = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. assert_equals: expected "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/" +FAIL <a>: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments. assert_equals: expected "http://example.net/%2e%2E%c3%89t%C3%A9" but got "http://example.net/..%c3%89t%C3%A9" +FAIL <area>: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments. assert_equals: expected "http://example.net/%2e%2E%c3%89t%C3%A9" but got "http://example.net/..%c3%89t%C3%A9" +PASS <a>: Setting <http://example.net>.pathname = '?' ? needs to be encoded +PASS <area>: Setting <http://example.net>.pathname = '?' ? needs to be encoded +PASS <a>: Setting <http://example.net>.pathname = '#' # needs to be encoded +PASS <area>: Setting <http://example.net>.pathname = '#' # needs to be encoded +FAIL <a>: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%3F" but got "sc://example.net" +FAIL <area>: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%3F" but got "sc://example.net" +FAIL <a>: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%23" but got "sc://example.net" +FAIL <area>: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%23" but got "sc://example.net" +PASS <a>: Setting <file://monkey/>.pathname = '\\' File URLs and (back)slashes +PASS <area>: Setting <file://monkey/>.pathname = '\\' File URLs and (back)slashes +FAIL <a>: Setting <file:///unicorn>.pathname = '//\/' File URLs and (back)slashes assert_equals: expected "file://////" but got "file:///" +FAIL <area>: Setting <file:///unicorn>.pathname = '//\/' File URLs and (back)slashes assert_equals: expected "file://////" but got "file:///" +FAIL <a>: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes assert_equals: expected "file://///" but got "file:///" +FAIL <area>: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes assert_equals: expected "file://///" but got "file:///" +FAIL <a>: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <area>: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <a>: Setting <non-spec:/>.pathname = '/..//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <area>: Setting <non-spec:/>.pathname = '/..//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <a>: Setting <non-spec:/>.pathname = '//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <area>: Setting <non-spec:/>.pathname = '//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL <a>: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path assert_equals: expected "non-spec:/p" but got "non-spec:/.//" +FAIL <area>: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path assert_equals: expected "non-spec:/p" but got "non-spec:/.//" +PASS <a>: Setting <https://example.net#nav>.search = 'lang=fr' +PASS <area>: Setting <https://example.net#nav>.search = 'lang=fr' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr' +FAIL <a>: Setting <https://example.net?lang=en-US#nav>.search = '?' assert_equals: expected "https://example.net/?#nav" but got "https://example.net/#nav" +FAIL <area>: Setting <https://example.net?lang=en-US#nav>.search = '?' assert_equals: expected "https://example.net/?#nav" but got "https://example.net/#nav" +PASS <a>: Setting <https://example.net?lang=en-US#nav>.search = '' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.search = '' +PASS <a>: Setting <https://example.net?lang=en-US>.search = '' +PASS <area>: Setting <https://example.net?lang=en-US>.search = '' +PASS <a>: Setting <https://example.net>.search = '' +PASS <area>: Setting <https://example.net>.search = '' +FAIL <a>: Setting <a:/>.search = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +FAIL <area>: Setting <a:/>.search = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS <a>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is +PASS <area>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is +PASS <a>: Setting <https://example.net>.hash = 'main' +PASS <area>: Setting <https://example.net>.hash = 'main' +PASS <a>: Setting <https://example.net#nav>.hash = 'main' +PASS <area>: Setting <https://example.net#nav>.hash = 'main' +PASS <a>: Setting <https://example.net?lang=en-US>.hash = '##nav' +PASS <area>: Setting <https://example.net?lang=en-US>.hash = '##nav' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = '#main' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = '#main' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = '#' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = '#' +PASS <a>: Setting <https://example.net?lang=en-US#nav>.hash = '' +PASS <area>: Setting <https://example.net?lang=en-US#nav>.hash = '' +PASS <a>: Setting <http://example.net>.hash = '#foo bar' +PASS <area>: Setting <http://example.net>.hash = '#foo bar' +PASS <a>: Setting <http://example.net>.hash = '#foo"bar' +PASS <area>: Setting <http://example.net>.hash = '#foo"bar' +PASS <a>: Setting <http://example.net>.hash = '#foo<bar' +PASS <area>: Setting <http://example.net>.hash = '#foo<bar' +PASS <a>: Setting <http://example.net>.hash = '#foo>bar' +PASS <area>: Setting <http://example.net>.hash = '#foo>bar' +PASS <a>: Setting <http://example.net>.hash = '#foo`bar' +PASS <area>: Setting <http://example.net>.hash = '#foo`bar' +FAIL <a>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +FAIL <area>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS <a>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS <area>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS <a>: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS <area>: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS <a>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is +PASS <area>: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is +PASS <a>: Setting <javascript:alert(1)>.hash = 'castle' +PASS <area>: Setting <javascript:alert(1)>.hash = 'castle' +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any-expected.txt new file mode 100644 index 0000000..326d569 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any-expected.txt
@@ -0,0 +1,218 @@ +This is a testharness.js-based test. +Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Loading data… +PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. +PASS URL: Setting <a://example.net>.protocol = 'b' +PASS URL: Setting <javascript:alert(1)>.protocol = 'defuse' +PASS URL: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased +PASS URL: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected +PASS URL: Setting <a://example.net>.protocol = '0b' No leading digit +PASS URL: Setting <a://example.net>.protocol = '+b' No leading punctuation +PASS URL: Setting <a://example.net>.protocol = 'bC0+-.' +PASS URL: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable +PASS URL: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected +PASS URL: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file +PASS URL: Setting <https://example.net:1234>.protocol = 'file' +PASS URL: Setting <wss://x:x@example.net:1234>.protocol = 'file' +FAIL URL: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host assert_equals: expected "file:///" but got "http://localhost/" +PASS URL: Setting <file:///test>.protocol = 'https' +PASS URL: Setting <file:>.protocol = 'wss' +FAIL URL: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special assert_equals: expected "http://example.net/" but got "b://example.net/" +FAIL URL: Setting <file://hi/path>.protocol = 's' assert_equals: expected "file://hi/path" but got "s://hi/path" +FAIL URL: Setting <https://example.net>.protocol = 's' assert_equals: expected "https://example.net/" but got "s://example.net/" +FAIL URL: Setting <ftp://example.net>.protocol = 'test' assert_equals: expected "ftp://example.net/" but got "test://example.net/" +FAIL URL: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must. assert_equals: expected "mailto:me@example.net" but got "http://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'https' assert_equals: expected "ssh://me@example.net" but got "https://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'file' assert_equals: expected "ssh://me@example.net" but got "file://me%40example.net/" +FAIL URL: Setting <ssh://example.net>.protocol = 'file' assert_equals: expected "ssh://example.net" but got "file://example.net/" +FAIL URL: Setting <nonsense:///test>.protocol = 'https' assert_equals: expected "nonsense:///test" but got "https://test/" +PASS URL: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored +PASS URL: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored +PASS URL: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme. +PASS URL: Setting <file:///home/you/index.html>.username = 'me' No host means no username +PASS URL: Setting <unix:/run/foo.socket>.username = 'me' No host means no username +PASS URL: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username +PASS URL: Setting <javascript:alert(1)>.username = 'wario' +PASS URL: Setting <http://example.net>.username = 'me' +PASS URL: Setting <http://:secret@example.net>.username = 'me' +PASS URL: Setting <http://me@example.net>.username = '' +PASS URL: Setting <http://me:secret@example.net>.username = '' +FAIL URL: Setting <http://example.net>.username = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS URL: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS URL: Setting <sc:///>.username = 'x' +FAIL URL: Setting <javascript://x/>.username = 'wario' assert_equals: expected "javascript://wario@x/" but got "javascript://x/" +PASS URL: Setting <file://test/>.username = 'test' +PASS URL: Setting <file:///home/me/index.html>.password = 'secret' No host means no password +PASS URL: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password +PASS URL: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password +PASS URL: Setting <http://example.net>.password = 'secret' +PASS URL: Setting <http://me@example.net>.password = 'secret' +PASS URL: Setting <http://:secret@example.net>.password = '' +PASS URL: Setting <http://me:secret@example.net>.password = '' +FAIL URL: Setting <http://example.net>.password = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS URL: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS URL: Setting <sc:///>.password = 'x' +FAIL URL: Setting <javascript://x/>.password = 'bowser' assert_equals: expected "javascript://:bowser@x/" but got "javascript://x/" +PASS URL: Setting <file://test/>.password = 'test' +FAIL URL: Setting <sc://x/>.host = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = ' ' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '@' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = 'ß' assert_equals: expected "sc://%C3%9F/" but got "sc://x/" +FAIL URL: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing assert_equals: expected "https://xn--zca/" but got "https://ss/" +PASS URL: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host +PASS URL: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host +PASS URL: Setting <http://example.net>.host = 'example.com:8080' +PASS URL: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value +PASS URL: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified +PASS URL: Setting <http://example.net>.host = '' The empty host is not valid for special schemes +FAIL URL: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL URL: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS URL: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized +PASS URL: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized +PASS URL: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416 +PASS URL: Setting <http://example.net>.host = 'example.com:80' Default port number is removed +PASS URL: Setting <https://example.net>.host = 'example.com:443' Default port number is removed +PASS URL: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme +PASS URL: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port +PASS URL: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.host = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +FAIL URL: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.com:8080/path" but got "view-source+http://example.net/path" +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers +PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. +PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 +PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]' +FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +FAIL URL: Setting <file://y/>.host = 'x:123' assert_equals: expected "file://y/" but got "file://x/" +FAIL URL: Setting <file://y/>.host = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL URL: Setting <file://hi/x>.host = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got "" +FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got "" +FAIL URL: Setting <sc://x/>.hostname = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.hostname = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = ' ' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.hostname = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '@' assert_equals: expected "x" but got "" +PASS URL: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host +PASS URL: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host +PASS URL: Setting <http://example.net:8080>.hostname = 'example.com' +PASS URL: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes +FAIL URL: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL URL: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS URL: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized +PASS URL: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized +PASS URL: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value +PASS URL: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value +PASS URL: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6 +PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]' +FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +PASS URL: Setting <file://y/>.hostname = 'x:123' +FAIL URL: Setting <file://y/>.hostname = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL URL: Setting <file://hi/x>.hostname = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got "" +FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got "" +FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p" +FAIL URL: Setting <non-spec:/.//p>.hostname = '' assert_equals: expected "non-spec:////p" but got "non-spec:/.//p" +PASS URL: Setting <http://example.net>.port = '8080' +PASS URL: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value +PASS URL: Setting <http://example.net:8080>.port = '80' Default port number is removed +PASS URL: Setting <https://example.net:4433>.port = '443' Default port number is removed +PASS URL: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme +PASS URL: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.net:8080/path" but got "view-source+http://example.net/path" +PASS URL: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers +FAIL URL: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path" +FAIL URL: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "example.net:8080" but got "" +PASS URL: Setting <file://test/>.port = '12' +FAIL URL: Setting <file://localhost/>.port = '12' assert_equals: expected "file:///" but got "file://localhost/" +PASS URL: Setting <non-base:value>.port = '12' +PASS URL: Setting <sc:///>.port = '12' +FAIL URL: Setting <sc://x/>.port = '12' assert_equals: expected "sc://x:12/" but got "sc://x/" +FAIL URL: Setting <javascript://x/>.port = '12' assert_equals: expected "javascript://x:12/" but got "javascript://x/" +PASS URL: Setting <mailto:me@example.net>.pathname = '/foo' Cannot-be-a-base don’t have a path +FAIL URL: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket' assert_equals: expected "unix:/var/run/bar.socket?timeout=10" but got "unix:/run/foo.socket?timeout=10" +PASS URL: Setting <https://example.net#nav>.pathname = 'home' +PASS URL: Setting <https://example.net#nav>.pathname = '../home' +PASS URL: Setting <http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is a segment delimiter for 'special' URLs +FAIL URL: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is *not* a segment delimiter for non-'special' URLs assert_equals: expected "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav" but got "view-source+http://example.net/home?lang=fr#nav" +FAIL URL: Setting <a:/>.pathname = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. assert_equals: expected "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/" +FAIL URL: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments. assert_equals: expected "http://example.net/%2e%2E%c3%89t%C3%A9" but got "http://example.net/..%c3%89t%C3%A9" +PASS URL: Setting <http://example.net>.pathname = '?' ? needs to be encoded +PASS URL: Setting <http://example.net>.pathname = '#' # needs to be encoded +FAIL URL: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%3F" but got "sc://example.net" +FAIL URL: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%23" but got "sc://example.net" +PASS URL: Setting <file://monkey/>.pathname = '\\' File URLs and (back)slashes +PASS URL: Setting <file:///unicorn>.pathname = '//\/' File URLs and (back)slashes +PASS URL: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes +FAIL URL: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/>.pathname = '/..//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/>.pathname = '//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path assert_equals: expected "non-spec:/p" but got "non-spec:/.//" +PASS URL: Setting <https://example.net#nav>.search = 'lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr' +FAIL URL: Setting <https://example.net?lang=en-US#nav>.search = '?' assert_equals: expected "https://example.net/?#nav" but got "https://example.net/#nav" +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '' +PASS URL: Setting <https://example.net?lang=en-US>.search = '' +PASS URL: Setting <https://example.net>.search = '' +FAIL URL: Setting <a:/>.search = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is +PASS URL: Setting <https://example.net>.hash = 'main' +PASS URL: Setting <https://example.net#nav>.hash = 'main' +PASS URL: Setting <https://example.net?lang=en-US>.hash = '##nav' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '#main' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '#' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '' +PASS URL: Setting <http://example.net>.hash = '#foo bar' +PASS URL: Setting <http://example.net>.hash = '#foo"bar' +PASS URL: Setting <http://example.net>.hash = '#foo<bar' +PASS URL: Setting <http://example.net>.hash = '#foo>bar' +PASS URL: Setting <http://example.net>.hash = '#foo`bar' +FAIL URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is +PASS URL: Setting <javascript:alert(1)>.hash = 'castle' +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any.worker-expected.txt new file mode 100644 index 0000000..326d569 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/url/url-setters.any.worker-expected.txt
@@ -0,0 +1,218 @@ +This is a testharness.js-based test. +Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Loading data… +PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. +PASS URL: Setting <a://example.net>.protocol = 'b' +PASS URL: Setting <javascript:alert(1)>.protocol = 'defuse' +PASS URL: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased +PASS URL: Setting <a://example.net>.protocol = 'é' Non-ASCII is rejected +PASS URL: Setting <a://example.net>.protocol = '0b' No leading digit +PASS URL: Setting <a://example.net>.protocol = '+b' No leading punctuation +PASS URL: Setting <a://example.net>.protocol = 'bC0+-.' +PASS URL: Setting <a://example.net>.protocol = 'b,c' Only some punctuation is acceptable +PASS URL: Setting <a://example.net>.protocol = 'bé' Non-ASCII is rejected +PASS URL: Setting <http://test@example.net>.protocol = 'file' Can’t switch from URL containing username/password/port to file +PASS URL: Setting <https://example.net:1234>.protocol = 'file' +PASS URL: Setting <wss://x:x@example.net:1234>.protocol = 'file' +FAIL URL: Setting <file://localhost/>.protocol = 'http' Can’t switch from file URL with no host assert_equals: expected "file:///" but got "http://localhost/" +PASS URL: Setting <file:///test>.protocol = 'https' +PASS URL: Setting <file:>.protocol = 'wss' +FAIL URL: Setting <http://example.net>.protocol = 'b' Can’t switch from special scheme to non-special assert_equals: expected "http://example.net/" but got "b://example.net/" +FAIL URL: Setting <file://hi/path>.protocol = 's' assert_equals: expected "file://hi/path" but got "s://hi/path" +FAIL URL: Setting <https://example.net>.protocol = 's' assert_equals: expected "https://example.net/" but got "s://example.net/" +FAIL URL: Setting <ftp://example.net>.protocol = 'test' assert_equals: expected "ftp://example.net/" but got "test://example.net/" +FAIL URL: Setting <mailto:me@example.net>.protocol = 'http' Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must. assert_equals: expected "mailto:me@example.net" but got "http://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'https' assert_equals: expected "ssh://me@example.net" but got "https://me@example.net/" +FAIL URL: Setting <ssh://me@example.net>.protocol = 'file' assert_equals: expected "ssh://me@example.net" but got "file://me%40example.net/" +FAIL URL: Setting <ssh://example.net>.protocol = 'file' assert_equals: expected "ssh://example.net" but got "file://example.net/" +FAIL URL: Setting <nonsense:///test>.protocol = 'https' assert_equals: expected "nonsense:///test" but got "https://test/" +PASS URL: Setting <http://example.net>.protocol = 'https:foo : bar' Stuff after the first ':' is ignored +PASS URL: Setting <data:text/html,<p>Test>.protocol = 'view-source+data:foo : bar' Stuff after the first ':' is ignored +PASS URL: Setting <http://foo.com:443/>.protocol = 'https' Port is set to null if it is the default for new scheme. +PASS URL: Setting <file:///home/you/index.html>.username = 'me' No host means no username +PASS URL: Setting <unix:/run/foo.socket>.username = 'me' No host means no username +PASS URL: Setting <mailto:you@example.net>.username = 'me' Cannot-be-a-base means no username +PASS URL: Setting <javascript:alert(1)>.username = 'wario' +PASS URL: Setting <http://example.net>.username = 'me' +PASS URL: Setting <http://:secret@example.net>.username = 'me' +PASS URL: Setting <http://me@example.net>.username = '' +PASS URL: Setting <http://me:secret@example.net>.username = '' +FAIL URL: Setting <http://example.net>.username = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS URL: Setting <http://example.net>.username = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS URL: Setting <sc:///>.username = 'x' +FAIL URL: Setting <javascript://x/>.username = 'wario' assert_equals: expected "javascript://wario@x/" but got "javascript://x/" +PASS URL: Setting <file://test/>.username = 'test' +PASS URL: Setting <file:///home/me/index.html>.password = 'secret' No host means no password +PASS URL: Setting <unix:/run/foo.socket>.password = 'secret' No host means no password +PASS URL: Setting <mailto:me@example.net>.password = 'secret' Cannot-be-a-base means no password +PASS URL: Setting <http://example.net>.password = 'secret' +PASS URL: Setting <http://me@example.net>.password = 'secret' +PASS URL: Setting <http://:secret@example.net>.password = '' +PASS URL: Setting <http://me:secret@example.net>.password = '' +FAIL URL: Setting <http://example.net>.password = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the userinfo encode set. assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" +PASS URL: Setting <http://example.net>.password = '%c3%89té' Bytes already percent-encoded are left as-is. +PASS URL: Setting <sc:///>.password = 'x' +FAIL URL: Setting <javascript://x/>.password = 'bowser' assert_equals: expected "javascript://:bowser@x/" but got "javascript://x/" +PASS URL: Setting <file://test/>.password = 'test' +FAIL URL: Setting <sc://x/>.host = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = ' ' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.host = '@' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.host = 'ß' assert_equals: expected "sc://%C3%9F/" but got "sc://x/" +FAIL URL: Setting <https://x/>.host = 'ß' IDNA Nontransitional_Processing assert_equals: expected "https://xn--zca/" but got "https://ss/" +PASS URL: Setting <mailto:me@example.net>.host = 'example.com' Cannot-be-a-base means no host +PASS URL: Setting <data:text/plain,Stuff>.host = 'example.net' Cannot-be-a-base means no host +PASS URL: Setting <http://example.net>.host = 'example.com:8080' +PASS URL: Setting <http://example.net:8080>.host = 'example.com' Port number is unchanged if not specified in the new value +PASS URL: Setting <http://example.net:8080>.host = 'example.com:' Port number is unchanged if not specified +PASS URL: Setting <http://example.net>.host = '' The empty host is not valid for special schemes +FAIL URL: Setting <view-source+http://example.net/foo>.host = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL URL: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS URL: Setting <http://example.net>.host = '0x7F000001:8080' IPv4 address syntax is normalized +PASS URL: Setting <http://example.net>.host = '[::0:01]:2' IPv6 address syntax is normalized +PASS URL: Setting <http://example.net>.host = '[2001:db8::2]:4002' IPv6 literal address with port, crbug.com/1012416 +PASS URL: Setting <http://example.net>.host = 'example.com:80' Default port number is removed +PASS URL: Setting <https://example.net>.host = 'example.com:443' Default port number is removed +PASS URL: Setting <https://example.net>.host = 'example.com:80' Default port number is only removed for the relevant scheme +PASS URL: Setting <http://example.net:8080>.host = 'example.com:80' Port number is removed if new port is scheme default and existing URL has a non-default port +PASS URL: Setting <http://example.net/path>.host = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.host = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.host = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +FAIL URL: Setting <view-source+http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.com:8080/path" but got "view-source+http://example.net/path" +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.host = 'example.com:8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.host = 'example.com:65535' Port numbers are 16 bit integers +PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though. +PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6 +PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]' +FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +FAIL URL: Setting <file://y/>.host = 'x:123' assert_equals: expected "file://y/" but got "file://x/" +FAIL URL: Setting <file://y/>.host = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL URL: Setting <file://hi/x>.host = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got "" +FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got "" +FAIL URL: Setting <sc://x/>.hostname = '\0' Non-special scheme assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.hostname = ' ' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = ' +' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '\r' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = ' ' assert_equals: expected "x" but got "" +FAIL URL: Setting <sc://x/>.hostname = '#' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '/' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '?' assert_equals: expected "sc:///" but got "sc://x/" +FAIL URL: Setting <sc://x/>.hostname = '@' assert_equals: expected "x" but got "" +PASS URL: Setting <mailto:me@example.net>.hostname = 'example.com' Cannot-be-a-base means no host +PASS URL: Setting <data:text/plain,Stuff>.hostname = 'example.net' Cannot-be-a-base means no host +PASS URL: Setting <http://example.net:8080>.hostname = 'example.com' +PASS URL: Setting <http://example.net>.hostname = '' The empty host is not valid for special schemes +FAIL URL: Setting <view-source+http://example.net/foo>.hostname = '' The empty host is OK for non-special schemes assert_equals: expected "view-source+http:///foo" but got "view-source+http://example.net/foo" +FAIL URL: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host assert_equals: expected "a://example.net/foo" but got "a:/foo" +PASS URL: Setting <http://example.net:8080>.hostname = '0x7F000001' IPv4 address syntax is normalized +PASS URL: Setting <http://example.net>.hostname = '[::0:01]' IPv6 address syntax is normalized +PASS URL: Setting <http://example.net/path>.hostname = 'example.com:8080' : delimiter invalidates entire value +PASS URL: Setting <http://example.net:8080/path>.hostname = 'example.com:' : delimiter invalidates entire value +PASS URL: Setting <http://example.net/path>.hostname = 'example.com/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.hostname = 'example.com\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got "" +PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6 +PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]' +FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/" +FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/" +FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/" +PASS URL: Setting <file://y/>.hostname = 'x:123' +FAIL URL: Setting <file://y/>.hostname = 'loc%41lhost' assert_equals: expected "file:///" but got "file://localhost/" +FAIL URL: Setting <file://hi/x>.hostname = '' assert_equals: expected "file:///x" but got "file://hi/x" +FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got "" +FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got "" +FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p" +FAIL URL: Setting <non-spec:/.//p>.hostname = '' assert_equals: expected "non-spec:////p" but got "non-spec:/.//p" +PASS URL: Setting <http://example.net>.port = '8080' +PASS URL: Setting <http://example.net:8080>.port = '' Port number is removed if empty is the new value +PASS URL: Setting <http://example.net:8080>.port = '80' Default port number is removed +PASS URL: Setting <https://example.net:4433>.port = '443' Default port number is removed +PASS URL: Setting <https://example.net>.port = '80' Default port number is only removed for the relevant scheme +PASS URL: Setting <http://example.net/path>.port = '8080/stuff' Stuff after a / delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080?stuff' Stuff after a ? delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080#stuff' Stuff after a # delimiter is ignored +PASS URL: Setting <http://example.net/path>.port = '8080\stuff' Stuff after a \ delimiter is ignored for special schemes +FAIL URL: Setting <view-source+http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error assert_equals: expected "view-source+http://example.net:8080/path" but got "view-source+http://example.net/path" +PASS URL: Setting <http://example.net/path>.port = '8080stuff2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.port = '8080+2' Anything other than ASCII digit stops the port parser in a setter but is not an error +PASS URL: Setting <http://example.net/path>.port = '65535' Port numbers are 16 bit integers +FAIL URL: Setting <http://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "http://example.net:8080/path" but got "http://example.net:0/path" +FAIL URL: Setting <non-special://example.net:8080/path>.port = '65536' Port numbers are 16 bit integers, overflowing is an error assert_equals: expected "example.net:8080" but got "" +PASS URL: Setting <file://test/>.port = '12' +FAIL URL: Setting <file://localhost/>.port = '12' assert_equals: expected "file:///" but got "file://localhost/" +PASS URL: Setting <non-base:value>.port = '12' +PASS URL: Setting <sc:///>.port = '12' +FAIL URL: Setting <sc://x/>.port = '12' assert_equals: expected "sc://x:12/" but got "sc://x/" +FAIL URL: Setting <javascript://x/>.port = '12' assert_equals: expected "javascript://x:12/" but got "javascript://x/" +PASS URL: Setting <mailto:me@example.net>.pathname = '/foo' Cannot-be-a-base don’t have a path +FAIL URL: Setting <unix:/run/foo.socket?timeout=10>.pathname = '/var/log/../run/bar.socket' assert_equals: expected "unix:/var/run/bar.socket?timeout=10" but got "unix:/run/foo.socket?timeout=10" +PASS URL: Setting <https://example.net#nav>.pathname = 'home' +PASS URL: Setting <https://example.net#nav>.pathname = '../home' +PASS URL: Setting <http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is a segment delimiter for 'special' URLs +FAIL URL: Setting <view-source+http://example.net/home?lang=fr#nav>.pathname = '\a\%2E\b\%2e.\c' \ is *not* a segment delimiter for non-'special' URLs assert_equals: expected "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav" but got "view-source+http://example.net/home?lang=fr#nav" +FAIL URL: Setting <a:/>.pathname = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. assert_equals: expected "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/" +FAIL URL: Setting <http://example.net>.pathname = '%2e%2E%c3%89té' Bytes already percent-encoded are left as-is, including %2E outside dotted segments. assert_equals: expected "http://example.net/%2e%2E%c3%89t%C3%A9" but got "http://example.net/..%c3%89t%C3%A9" +PASS URL: Setting <http://example.net>.pathname = '?' ? needs to be encoded +PASS URL: Setting <http://example.net>.pathname = '#' # needs to be encoded +FAIL URL: Setting <sc://example.net>.pathname = '?' ? needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%3F" but got "sc://example.net" +FAIL URL: Setting <sc://example.net>.pathname = '#' # needs to be encoded, non-special scheme assert_equals: expected "sc://example.net/%23" but got "sc://example.net" +PASS URL: Setting <file://monkey/>.pathname = '\\' File URLs and (back)slashes +PASS URL: Setting <file:///unicorn>.pathname = '//\/' File URLs and (back)slashes +PASS URL: Setting <file:///unicorn>.pathname = '//monkey/..//' File URLs and (back)slashes +FAIL URL: Setting <non-spec:/>.pathname = '/.//p' Serialize /. in path assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/>.pathname = '/..//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/>.pathname = '//p' assert_equals: expected "non-spec:/.//p" but got "non-spec:/" +FAIL URL: Setting <non-spec:/.//>.pathname = 'p' Drop /. from path assert_equals: expected "non-spec:/p" but got "non-spec:/.//" +PASS URL: Setting <https://example.net#nav>.search = 'lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = 'lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '?lang=fr' +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '??lang=fr' +FAIL URL: Setting <https://example.net?lang=en-US#nav>.search = '?' assert_equals: expected "https://example.net/?#nav" but got "https://example.net/#nav" +PASS URL: Setting <https://example.net?lang=en-US#nav>.search = '' +PASS URL: Setting <https://example.net?lang=en-US>.search = '' +PASS URL: Setting <https://example.net>.search = '' +FAIL URL: Setting <a:/>.search = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is +PASS URL: Setting <https://example.net>.hash = 'main' +PASS URL: Setting <https://example.net#nav>.hash = 'main' +PASS URL: Setting <https://example.net?lang=en-US>.hash = '##nav' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '#main' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '#' +PASS URL: Setting <https://example.net?lang=en-US#nav>.hash = '' +PASS URL: Setting <http://example.net>.hash = '#foo bar' +PASS URL: Setting <http://example.net>.hash = '#foo"bar' +PASS URL: Setting <http://example.net>.hash = '#foo<bar' +PASS URL: Setting <http://example.net>.hash = '#foo>bar' +PASS URL: Setting <http://example.net>.hash = '#foo`bar' +FAIL URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment +PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is +PASS URL: Setting <javascript:alert(1)>.hash = 'castle' +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt new file mode 100644 index 0000000..ce5ff0d0 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -0,0 +1,81 @@ +This is a testharness.js-based test. +Found 77 tests; 70 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS getStats succeeds +PASS Validating stats +PASS RTCRtpStreamStats's ssrc +PASS RTCRtpStreamStats's kind +PASS RTCRtpStreamStats's transportId +PASS RTCRtpStreamStats's codecId +PASS RTCReceivedRtpStreamStats's packetsReceived +PASS RTCReceivedRtpStreamStats's packetsLost +PASS RTCReceivedRtpStreamStats's jitter +FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false +PASS RTCReceivedRtpStreamStats's framesDropped +FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false +PASS RTCInboundRtpStreamStats's remoteId +PASS RTCInboundRtpStreamStats's framesDecoded +PASS RTCInboundRtpStreamStats's nackCount +PASS RTCInboundRtpStreamStats's framesReceived +PASS RTCInboundRtpStreamStats's bytesReceived +PASS RTCInboundRtpStreamStats's totalAudioEnergy +PASS RTCInboundRtpStreamStats's totalSamplesDuration +PASS RTCRemoteInboundRtpStreamStats's localId +PASS RTCRemoteInboundRtpStreamStats's roundTripTime +PASS RTCSentRtpStreamStats's packetsSent +PASS RTCSentRtpStreamStats's bytesSent +FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false +PASS RTCOutboundRtpStreamStats's remoteId +PASS RTCOutboundRtpStreamStats's framesEncoded +PASS RTCOutboundRtpStreamStats's nackCount +PASS RTCOutboundRtpStreamStats's framesSent +PASS RTCRemoteOutboundRtpStreamStats's localId +PASS RTCRemoteOutboundRtpStreamStats's remoteTimestamp +PASS RTCPeerConnectionStats's dataChannelsOpened +PASS RTCPeerConnectionStats's dataChannelsClosed +PASS RTCDataChannelStats's label +PASS RTCDataChannelStats's protocol +PASS RTCDataChannelStats's dataChannelIdentifier +PASS RTCDataChannelStats's state +PASS RTCDataChannelStats's messagesSent +PASS RTCDataChannelStats's bytesSent +PASS RTCDataChannelStats's messagesReceived +PASS RTCDataChannelStats's bytesReceived +PASS RTCMediaSourceStats's trackIdentifier +PASS RTCMediaSourceStats's kind +PASS RTCAudioSourceStats's totalAudioEnergy +PASS RTCAudioSourceStats's totalSamplesDuration +PASS RTCVideoSourceStats's width +PASS RTCVideoSourceStats's height +PASS RTCVideoSourceStats's framesPerSecond +FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false +PASS RTCCodecStats's payloadType +FAIL RTCCodecStats's codecType assert_true: Is codecType present expected true got false +PASS RTCCodecStats's mimeType +PASS RTCCodecStats's clockRate +PASS RTCCodecStats's channels +PASS RTCCodecStats's sdpFmtpLine +PASS RTCTransportStats's bytesSent +PASS RTCTransportStats's bytesReceived +PASS RTCTransportStats's selectedCandidatePairId +PASS RTCTransportStats's localCertificateId +PASS RTCTransportStats's remoteCertificateId +PASS RTCIceCandidatePairStats's transportId +PASS RTCIceCandidatePairStats's localCandidateId +PASS RTCIceCandidatePairStats's remoteCandidateId +PASS RTCIceCandidatePairStats's state +PASS RTCIceCandidatePairStats's nominated +PASS RTCIceCandidatePairStats's bytesSent +PASS RTCIceCandidatePairStats's bytesReceived +PASS RTCIceCandidatePairStats's totalRoundTripTime +PASS RTCIceCandidatePairStats's currentRoundTripTime +PASS RTCIceCandidateStats's address +PASS RTCIceCandidateStats's port +PASS RTCIceCandidateStats's protocol +PASS RTCIceCandidateStats's candidateType +FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false +PASS RTCCertificateStats's fingerprint +PASS RTCCertificateStats's fingerprintAlgorithm +PASS RTCCertificateStats's base64Certificate +FAIL RTCCertificateStats's issuerCertificateId assert_true: Is issuerCertificateId present expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt new file mode 100644 index 0000000..f514bf73 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: stable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 +FAIL setLocalDescription(pranswer) should succeed assert_equals: expected null but got object "[object RTCSessionDescription]" +PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer +PASS setLocalDescription(answer) from have-local-pranswer state should succeed +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webxr/idlharness.https.window-expected.txt new file mode 100644 index 0000000..bd78477 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -0,0 +1,285 @@ +This is a testharness.js-based test. +Found 281 tests; 270 PASS, 11 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS idl_test setup +PASS idl_test validation +PASS Partial interface Navigator: original interface defined +PASS Partial interface Navigator: member names are unique +PASS Partial dictionary WebGLContextAttributes: original dictionary defined +PASS Partial dictionary WebGLContextAttributes: member names are unique +PASS Partial interface mixin WebGLRenderingContextBase: original interface mixin defined +PASS Partial interface mixin WebGLRenderingContextBase: member names are unique +PASS Partial interface Navigator[2]: member names are unique +PASS Partial interface mixin NavigatorID: member names are unique +FAIL WebGLRenderingContext includes WebGLRenderingContextBase: member names are unique assert_true: member canvas is unique expected true got false +FAIL WebGLRenderingContext includes WebGLRenderingContextOverloads: member names are unique assert_true: member bufferData is unique expected true got false +PASS Navigator includes NavigatorID: member names are unique +PASS Navigator includes NavigatorLanguage: member names are unique +PASS Navigator includes NavigatorOnLine: member names are unique +PASS Navigator includes NavigatorContentUtils: member names are unique +PASS Navigator includes NavigatorCookies: member names are unique +PASS Navigator includes NavigatorPlugins: member names are unique +PASS Navigator includes NavigatorConcurrentHardware: member names are unique +PASS XRSystem interface: existence and properties of interface object +PASS XRSystem interface object length +PASS XRSystem interface object name +PASS XRSystem interface: existence and properties of interface prototype object +PASS XRSystem interface: existence and properties of interface prototype object's "constructor" property +PASS XRSystem interface: existence and properties of interface prototype object's @@unscopables property +PASS XRSystem interface: operation isSessionSupported(XRSessionMode) +PASS XRSystem interface: operation requestSession(XRSessionMode, optional XRSessionInit) +PASS XRSystem interface: attribute ondevicechange +PASS XRSession interface: existence and properties of interface object +PASS XRSession interface object length +PASS XRSession interface object name +PASS XRSession interface: existence and properties of interface prototype object +PASS XRSession interface: existence and properties of interface prototype object's "constructor" property +PASS XRSession interface: existence and properties of interface prototype object's @@unscopables property +PASS XRSession interface: attribute visibilityState +PASS XRSession interface: attribute renderState +PASS XRSession interface: attribute inputSources +PASS XRSession interface: operation updateRenderState(optional XRRenderStateInit) +PASS XRSession interface: operation requestReferenceSpace(XRReferenceSpaceType) +PASS XRSession interface: operation requestAnimationFrame(XRFrameRequestCallback) +PASS XRSession interface: operation cancelAnimationFrame(unsigned long) +PASS XRSession interface: operation end() +PASS XRSession interface: attribute onend +PASS XRSession interface: attribute oninputsourceschange +PASS XRSession interface: attribute onselect +PASS XRSession interface: attribute onselectstart +PASS XRSession interface: attribute onselectend +PASS XRSession interface: attribute onsqueeze +PASS XRSession interface: attribute onsqueezestart +PASS XRSession interface: attribute onsqueezeend +PASS XRSession interface: attribute onvisibilitychange +PASS XRSession must be primary interface of xrSession +PASS Stringification of xrSession +PASS XRSession interface: xrSession must inherit property "visibilityState" with the proper type +PASS XRSession interface: xrSession must inherit property "renderState" with the proper type +PASS XRSession interface: xrSession must inherit property "inputSources" with the proper type +PASS XRSession interface: xrSession must inherit property "updateRenderState(optional XRRenderStateInit)" with the proper type +PASS XRSession interface: calling updateRenderState(optional XRRenderStateInit) on xrSession with too few arguments must throw TypeError +PASS XRSession interface: xrSession must inherit property "requestReferenceSpace(XRReferenceSpaceType)" with the proper type +PASS XRSession interface: calling requestReferenceSpace(XRReferenceSpaceType) on xrSession with too few arguments must throw TypeError +PASS XRSession interface: xrSession must inherit property "requestAnimationFrame(XRFrameRequestCallback)" with the proper type +PASS XRSession interface: calling requestAnimationFrame(XRFrameRequestCallback) on xrSession with too few arguments must throw TypeError +PASS XRSession interface: xrSession must inherit property "cancelAnimationFrame(unsigned long)" with the proper type +PASS XRSession interface: calling cancelAnimationFrame(unsigned long) on xrSession with too few arguments must throw TypeError +PASS XRSession interface: xrSession must inherit property "end()" with the proper type +PASS XRSession interface: xrSession must inherit property "onend" with the proper type +PASS XRSession interface: xrSession must inherit property "oninputsourceschange" with the proper type +PASS XRSession interface: xrSession must inherit property "onselect" with the proper type +PASS XRSession interface: xrSession must inherit property "onselectstart" with the proper type +PASS XRSession interface: xrSession must inherit property "onselectend" with the proper type +PASS XRSession interface: xrSession must inherit property "onsqueeze" with the proper type +PASS XRSession interface: xrSession must inherit property "onsqueezestart" with the proper type +PASS XRSession interface: xrSession must inherit property "onsqueezeend" with the proper type +PASS XRSession interface: xrSession must inherit property "onvisibilitychange" with the proper type +PASS XRRenderState interface: existence and properties of interface object +PASS XRRenderState interface object length +PASS XRRenderState interface object name +PASS XRRenderState interface: existence and properties of interface prototype object +PASS XRRenderState interface: existence and properties of interface prototype object's "constructor" property +PASS XRRenderState interface: existence and properties of interface prototype object's @@unscopables property +PASS XRRenderState interface: attribute depthNear +PASS XRRenderState interface: attribute depthFar +PASS XRRenderState interface: attribute inlineVerticalFieldOfView +PASS XRRenderState interface: attribute baseLayer +PASS XRRenderState must be primary interface of xrRenderState +PASS Stringification of xrRenderState +PASS XRRenderState interface: xrRenderState must inherit property "depthNear" with the proper type +PASS XRRenderState interface: xrRenderState must inherit property "depthFar" with the proper type +PASS XRRenderState interface: xrRenderState must inherit property "inlineVerticalFieldOfView" with the proper type +PASS XRRenderState interface: xrRenderState must inherit property "baseLayer" with the proper type +PASS XRFrame interface: existence and properties of interface object +PASS XRFrame interface object length +PASS XRFrame interface object name +PASS XRFrame interface: existence and properties of interface prototype object +PASS XRFrame interface: existence and properties of interface prototype object's "constructor" property +PASS XRFrame interface: existence and properties of interface prototype object's @@unscopables property +PASS XRFrame interface: attribute session +PASS XRFrame interface: operation getViewerPose(XRReferenceSpace) +PASS XRFrame interface: operation getPose(XRSpace, XRSpace) +PASS XRSpace interface: existence and properties of interface object +PASS XRSpace interface object length +PASS XRSpace interface object name +PASS XRSpace interface: existence and properties of interface prototype object +PASS XRSpace interface: existence and properties of interface prototype object's "constructor" property +PASS XRSpace interface: existence and properties of interface prototype object's @@unscopables property +PASS XRReferenceSpace interface: existence and properties of interface object +PASS XRReferenceSpace interface object length +PASS XRReferenceSpace interface object name +PASS XRReferenceSpace interface: existence and properties of interface prototype object +PASS XRReferenceSpace interface: existence and properties of interface prototype object's "constructor" property +PASS XRReferenceSpace interface: existence and properties of interface prototype object's @@unscopables property +PASS XRReferenceSpace interface: operation getOffsetReferenceSpace(XRRigidTransform) +PASS XRReferenceSpace interface: attribute onreset +PASS XRReferenceSpace must be primary interface of xrReferenceSpace +PASS Stringification of xrReferenceSpace +PASS XRReferenceSpace interface: xrReferenceSpace must inherit property "getOffsetReferenceSpace(XRRigidTransform)" with the proper type +PASS XRReferenceSpace interface: calling getOffsetReferenceSpace(XRRigidTransform) on xrReferenceSpace with too few arguments must throw TypeError +PASS XRReferenceSpace interface: xrReferenceSpace must inherit property "onreset" with the proper type +PASS XRBoundedReferenceSpace interface: existence and properties of interface object +PASS XRBoundedReferenceSpace interface object length +PASS XRBoundedReferenceSpace interface object name +PASS XRBoundedReferenceSpace interface: existence and properties of interface prototype object +PASS XRBoundedReferenceSpace interface: existence and properties of interface prototype object's "constructor" property +PASS XRBoundedReferenceSpace interface: existence and properties of interface prototype object's @@unscopables property +PASS XRBoundedReferenceSpace interface: attribute boundsGeometry +PASS XRView interface: existence and properties of interface object +PASS XRView interface object length +PASS XRView interface object name +PASS XRView interface: existence and properties of interface prototype object +PASS XRView interface: existence and properties of interface prototype object's "constructor" property +PASS XRView interface: existence and properties of interface prototype object's @@unscopables property +PASS XRView interface: attribute eye +PASS XRView interface: attribute projectionMatrix +PASS XRView interface: attribute transform +PASS XRView interface: attribute recommendedViewportScale +PASS XRView interface: operation requestViewportScale(double?) +PASS XRViewport interface: existence and properties of interface object +PASS XRViewport interface object length +PASS XRViewport interface object name +PASS XRViewport interface: existence and properties of interface prototype object +PASS XRViewport interface: existence and properties of interface prototype object's "constructor" property +PASS XRViewport interface: existence and properties of interface prototype object's @@unscopables property +PASS XRViewport interface: attribute x +PASS XRViewport interface: attribute y +PASS XRViewport interface: attribute width +PASS XRViewport interface: attribute height +PASS XRRigidTransform interface: existence and properties of interface object +PASS XRRigidTransform interface object length +PASS XRRigidTransform interface object name +PASS XRRigidTransform interface: existence and properties of interface prototype object +PASS XRRigidTransform interface: existence and properties of interface prototype object's "constructor" property +PASS XRRigidTransform interface: existence and properties of interface prototype object's @@unscopables property +PASS XRRigidTransform interface: attribute position +PASS XRRigidTransform interface: attribute orientation +PASS XRRigidTransform interface: attribute matrix +PASS XRRigidTransform interface: attribute inverse +PASS XRRigidTransform must be primary interface of new XRRigidTransform() +PASS Stringification of new XRRigidTransform() +PASS XRRigidTransform interface: new XRRigidTransform() must inherit property "position" with the proper type +PASS XRRigidTransform interface: new XRRigidTransform() must inherit property "orientation" with the proper type +PASS XRRigidTransform interface: new XRRigidTransform() must inherit property "matrix" with the proper type +PASS XRRigidTransform interface: new XRRigidTransform() must inherit property "inverse" with the proper type +PASS XRPose interface: existence and properties of interface object +PASS XRPose interface object length +PASS XRPose interface object name +PASS XRPose interface: existence and properties of interface prototype object +PASS XRPose interface: existence and properties of interface prototype object's "constructor" property +PASS XRPose interface: existence and properties of interface prototype object's @@unscopables property +PASS XRPose interface: attribute transform +FAIL XRPose interface: attribute linearVelocity assert_true: The prototype object must have a property "linearVelocity" expected true got false +FAIL XRPose interface: attribute angularVelocity assert_true: The prototype object must have a property "angularVelocity" expected true got false +PASS XRPose interface: attribute emulatedPosition +PASS XRViewerPose interface: existence and properties of interface object +PASS XRViewerPose interface object length +PASS XRViewerPose interface object name +PASS XRViewerPose interface: existence and properties of interface prototype object +PASS XRViewerPose interface: existence and properties of interface prototype object's "constructor" property +PASS XRViewerPose interface: existence and properties of interface prototype object's @@unscopables property +PASS XRViewerPose interface: attribute views +PASS XRInputSource interface: existence and properties of interface object +PASS XRInputSource interface object length +PASS XRInputSource interface object name +PASS XRInputSource interface: existence and properties of interface prototype object +PASS XRInputSource interface: existence and properties of interface prototype object's "constructor" property +PASS XRInputSource interface: existence and properties of interface prototype object's @@unscopables property +PASS XRInputSource interface: attribute handedness +PASS XRInputSource interface: attribute targetRayMode +PASS XRInputSource interface: attribute targetRaySpace +PASS XRInputSource interface: attribute gripSpace +PASS XRInputSource interface: attribute profiles +PASS XRInputSourceArray interface: existence and properties of interface object +PASS XRInputSourceArray interface object length +PASS XRInputSourceArray interface object name +PASS XRInputSourceArray interface: existence and properties of interface prototype object +PASS XRInputSourceArray interface: existence and properties of interface prototype object's "constructor" property +PASS XRInputSourceArray interface: existence and properties of interface prototype object's @@unscopables property +PASS XRInputSourceArray interface: iterable<XRInputSource> +PASS XRInputSourceArray interface: attribute length +PASS XRInputSourceArray must be primary interface of xrInputSourceArray +PASS Stringification of xrInputSourceArray +PASS XRInputSourceArray interface: xrInputSourceArray must inherit property "length" with the proper type +PASS XRLayer interface: existence and properties of interface object +PASS XRLayer interface object length +PASS XRLayer interface object name +PASS XRLayer interface: existence and properties of interface prototype object +PASS XRLayer interface: existence and properties of interface prototype object's "constructor" property +PASS XRLayer interface: existence and properties of interface prototype object's @@unscopables property +PASS XRWebGLLayer interface: existence and properties of interface object +PASS XRWebGLLayer interface object length +PASS XRWebGLLayer interface object name +PASS XRWebGLLayer interface: existence and properties of interface prototype object +PASS XRWebGLLayer interface: existence and properties of interface prototype object's "constructor" property +PASS XRWebGLLayer interface: existence and properties of interface prototype object's @@unscopables property +PASS XRWebGLLayer interface: attribute antialias +PASS XRWebGLLayer interface: attribute ignoreDepthValues +PASS XRWebGLLayer interface: attribute framebuffer +PASS XRWebGLLayer interface: attribute framebufferWidth +PASS XRWebGLLayer interface: attribute framebufferHeight +PASS XRWebGLLayer interface: operation getViewport(XRView) +PASS XRWebGLLayer interface: operation getNativeFramebufferScaleFactor(XRSession) +PASS XRWebGLLayer must be primary interface of xrWebGLLayer +PASS Stringification of xrWebGLLayer +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "antialias" with the proper type +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "ignoreDepthValues" with the proper type +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebuffer" with the proper type +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebufferWidth" with the proper type +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "framebufferHeight" with the proper type +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "getViewport(XRView)" with the proper type +PASS XRWebGLLayer interface: calling getViewport(XRView) on xrWebGLLayer with too few arguments must throw TypeError +PASS XRWebGLLayer interface: xrWebGLLayer must inherit property "getNativeFramebufferScaleFactor(XRSession)" with the proper type +PASS XRWebGLLayer interface: calling getNativeFramebufferScaleFactor(XRSession) on xrWebGLLayer with too few arguments must throw TypeError +PASS XRSessionEvent interface: existence and properties of interface object +PASS XRSessionEvent interface object length +PASS XRSessionEvent interface object name +PASS XRSessionEvent interface: existence and properties of interface prototype object +PASS XRSessionEvent interface: existence and properties of interface prototype object's "constructor" property +PASS XRSessionEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS XRSessionEvent interface: attribute session +PASS XRSessionEvent must be primary interface of xrSessionEvent +PASS Stringification of xrSessionEvent +PASS XRSessionEvent interface: xrSessionEvent must inherit property "session" with the proper type +PASS XRInputSourceEvent interface: existence and properties of interface object +PASS XRInputSourceEvent interface object length +PASS XRInputSourceEvent interface object name +PASS XRInputSourceEvent interface: existence and properties of interface prototype object +PASS XRInputSourceEvent interface: existence and properties of interface prototype object's "constructor" property +PASS XRInputSourceEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS XRInputSourceEvent interface: attribute frame +PASS XRInputSourceEvent interface: attribute inputSource +PASS XRInputSourcesChangeEvent interface: existence and properties of interface object +PASS XRInputSourcesChangeEvent interface object length +PASS XRInputSourcesChangeEvent interface object name +PASS XRInputSourcesChangeEvent interface: existence and properties of interface prototype object +PASS XRInputSourcesChangeEvent interface: existence and properties of interface prototype object's "constructor" property +PASS XRInputSourcesChangeEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS XRInputSourcesChangeEvent interface: attribute session +PASS XRInputSourcesChangeEvent interface: attribute added +PASS XRInputSourcesChangeEvent interface: attribute removed +PASS XRInputSourcesChangeEvent must be primary interface of xrInputSourcesChangeEvent +PASS Stringification of xrInputSourcesChangeEvent +PASS XRInputSourcesChangeEvent interface: xrInputSourcesChangeEvent must inherit property "session" with the proper type +PASS XRInputSourcesChangeEvent interface: xrInputSourcesChangeEvent must inherit property "added" with the proper type +PASS XRInputSourcesChangeEvent interface: xrInputSourcesChangeEvent must inherit property "removed" with the proper type +PASS XRReferenceSpaceEvent interface: existence and properties of interface object +PASS XRReferenceSpaceEvent interface object length +PASS XRReferenceSpaceEvent interface object name +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object's "constructor" property +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS XRReferenceSpaceEvent interface: attribute referenceSpace +PASS XRReferenceSpaceEvent interface: attribute transform +FAIL XRPermissionStatus interface: existence and properties of interface object assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface object length assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface object name assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface: existence and properties of interface prototype object assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +FAIL XRPermissionStatus interface: attribute granted assert_own_property: self does not have own property "XRPermissionStatus" expected property "XRPermissionStatus" missing +PASS WebGLRenderingContextBase interface: webGLRenderingContextBase must inherit property "makeXRCompatible()" with the proper type +PASS Navigator interface: attribute xr +PASS Navigator interface: navigator must inherit property "xr" with the proper type +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt new file mode 100644 index 0000000..ce5ff0d0 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -0,0 +1,81 @@ +This is a testharness.js-based test. +Found 77 tests; 70 PASS, 7 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS getStats succeeds +PASS Validating stats +PASS RTCRtpStreamStats's ssrc +PASS RTCRtpStreamStats's kind +PASS RTCRtpStreamStats's transportId +PASS RTCRtpStreamStats's codecId +PASS RTCReceivedRtpStreamStats's packetsReceived +PASS RTCReceivedRtpStreamStats's packetsLost +PASS RTCReceivedRtpStreamStats's jitter +FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false +PASS RTCReceivedRtpStreamStats's framesDropped +FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false +PASS RTCInboundRtpStreamStats's remoteId +PASS RTCInboundRtpStreamStats's framesDecoded +PASS RTCInboundRtpStreamStats's nackCount +PASS RTCInboundRtpStreamStats's framesReceived +PASS RTCInboundRtpStreamStats's bytesReceived +PASS RTCInboundRtpStreamStats's totalAudioEnergy +PASS RTCInboundRtpStreamStats's totalSamplesDuration +PASS RTCRemoteInboundRtpStreamStats's localId +PASS RTCRemoteInboundRtpStreamStats's roundTripTime +PASS RTCSentRtpStreamStats's packetsSent +PASS RTCSentRtpStreamStats's bytesSent +FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false +PASS RTCOutboundRtpStreamStats's remoteId +PASS RTCOutboundRtpStreamStats's framesEncoded +PASS RTCOutboundRtpStreamStats's nackCount +PASS RTCOutboundRtpStreamStats's framesSent +PASS RTCRemoteOutboundRtpStreamStats's localId +PASS RTCRemoteOutboundRtpStreamStats's remoteTimestamp +PASS RTCPeerConnectionStats's dataChannelsOpened +PASS RTCPeerConnectionStats's dataChannelsClosed +PASS RTCDataChannelStats's label +PASS RTCDataChannelStats's protocol +PASS RTCDataChannelStats's dataChannelIdentifier +PASS RTCDataChannelStats's state +PASS RTCDataChannelStats's messagesSent +PASS RTCDataChannelStats's bytesSent +PASS RTCDataChannelStats's messagesReceived +PASS RTCDataChannelStats's bytesReceived +PASS RTCMediaSourceStats's trackIdentifier +PASS RTCMediaSourceStats's kind +PASS RTCAudioSourceStats's totalAudioEnergy +PASS RTCAudioSourceStats's totalSamplesDuration +PASS RTCVideoSourceStats's width +PASS RTCVideoSourceStats's height +PASS RTCVideoSourceStats's framesPerSecond +FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false +PASS RTCCodecStats's payloadType +FAIL RTCCodecStats's codecType assert_true: Is codecType present expected true got false +PASS RTCCodecStats's mimeType +PASS RTCCodecStats's clockRate +PASS RTCCodecStats's channels +PASS RTCCodecStats's sdpFmtpLine +PASS RTCTransportStats's bytesSent +PASS RTCTransportStats's bytesReceived +PASS RTCTransportStats's selectedCandidatePairId +PASS RTCTransportStats's localCertificateId +PASS RTCTransportStats's remoteCertificateId +PASS RTCIceCandidatePairStats's transportId +PASS RTCIceCandidatePairStats's localCandidateId +PASS RTCIceCandidatePairStats's remoteCandidateId +PASS RTCIceCandidatePairStats's state +PASS RTCIceCandidatePairStats's nominated +PASS RTCIceCandidatePairStats's bytesSent +PASS RTCIceCandidatePairStats's bytesReceived +PASS RTCIceCandidatePairStats's totalRoundTripTime +PASS RTCIceCandidatePairStats's currentRoundTripTime +PASS RTCIceCandidateStats's address +PASS RTCIceCandidateStats's port +PASS RTCIceCandidateStats's protocol +PASS RTCIceCandidateStats's candidateType +FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false +PASS RTCCertificateStats's fingerprint +PASS RTCCertificateStats's fingerprintAlgorithm +PASS RTCCertificateStats's base64Certificate +FAIL RTCCertificateStats's issuerCertificateId assert_true: Is issuerCertificateId present expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt new file mode 100644 index 0000000..f514bf73 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: stable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 +FAIL setLocalDescription(pranswer) should succeed assert_equals: expected null but got object "[object RTCSessionDescription]" +PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer +PASS setLocalDescription(answer) from have-local-pranswer state should succeed +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png index 0e5d90b..26dc97b 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png index 32822cfa..39f8b30 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png new file mode 100644 index 0000000..c130a33 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png new file mode 100644 index 0000000..f6ce9b5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters-a-area.window-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters-a-area.window-expected.txt index 21d9d9d..9a71787 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters-a-area.window-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters-a-area.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 413 tests; 253 PASS, 160 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 413 tests; 255 PASS, 158 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. @@ -388,9 +388,9 @@ PASS <a>: Setting <https://example.net>.search = '' PASS <area>: Setting <https://example.net>.search = '' FAIL <a>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" FAIL <area>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS <a>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <area>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <a>: Setting <https://example.net>.hash = 'main' @@ -415,10 +415,10 @@ PASS <area>: Setting <http://example.net>.hash = '#foo>bar' PASS <a>: Setting <http://example.net>.hash = '#foo`bar' PASS <area>: Setting <http://example.net>.hash = '#foo`bar' -FAIL <a>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" -FAIL <area>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS <a>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed +PASS <area>: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS <a>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <area>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <a>: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any-expected.txt index 326d569..92293f7 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 207 tests; 130 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS URL: Setting <a://example.net>.protocol = 'b' @@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -208,8 +208,8 @@ PASS URL: Setting <http://example.net>.hash = '#foo<bar' PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' -FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker-expected.txt index 326d569..92293f7 100644 --- a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 207 tests; 129 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 207 tests; 130 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Loading data… PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. PASS URL: Setting <a://example.net>.protocol = 'b' @@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%09%0A%0D%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/?%00%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -208,8 +208,8 @@ PASS URL: Setting <http://example.net>.hash = '#foo<bar' PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' -FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "a:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +PASS URL: Setting <a:/>.hash = '\0 +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window-expected.txt index 94720af..0ff51f4 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window-expected.txt
@@ -388,9 +388,9 @@ PASS <a>: Setting <https://example.net>.search = '' PASS <area>: Setting <https://example.net>.search = '' FAIL <a>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" FAIL <area>: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS <a>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <area>: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS <a>: Setting <https://example.net>.hash = 'main' @@ -416,9 +416,9 @@ PASS <a>: Setting <http://example.net>.hash = '#foo`bar' PASS <area>: Setting <http://example.net>.hash = '#foo`bar' FAIL <a>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" FAIL <area>: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS <a>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <area>: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS <a>: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any-expected.txt index 69a42e7..27cceba 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any-expected.txt
@@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -209,7 +209,7 @@ PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker-expected.txt index 69a42e7..27cceba 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker-expected.txt +++ b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker-expected.txt
@@ -195,7 +195,7 @@ PASS URL: Setting <https://example.net?lang=en-US>.search = '' PASS URL: Setting <https://example.net>.search = '' FAIL URL: Setting <a:/>.search = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. assert_equals: expected "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/?%00%01%1F%20!%22%23$%&%27()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.search = '%c3%89té' Bytes already percent-encoded are left as-is PASS URL: Setting <https://example.net>.hash = 'main' PASS URL: Setting <https://example.net#nav>.hash = 'main' @@ -209,7 +209,7 @@ PASS URL: Setting <http://example.net>.hash = '#foo>bar' PASS URL: Setting <http://example.net>.hash = '#foo`bar' FAIL URL: Setting <a:/>.hash = '\0 -\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%09%0A%0D%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" +\r !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~Éé' Simple percent-encoding; tabs and newlines are removed assert_equals: expected "a:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" but got "file:///A:/#%00%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" PASS URL: Setting <http://example.net>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <non-spec:/>.hash = 'a\0b' Percent-encode NULLs in fragment PASS URL: Setting <http://example.net>.hash = '%c3%89té' Bytes already percent-encoded are left as-is
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png index 5649521..8fb2d8a 100644 --- a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png index 450f365..670c6bd9 100644 --- a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1-SE/text-tspan-02-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png index 14f5aa0..7a3617ad 100644 --- a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/animate-elem-40-t-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png index 53a067f7..4d14b0d 100644 --- a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/W3C-SVG-1.1/metadata-example-01-b-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/accessibility/scroll-window-horiz-sends-notification-expected.txt b/third_party/blink/web_tests/platform/win7/accessibility/scroll-window-horiz-sends-notification-expected.txt new file mode 100644 index 0000000..66b9632 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/accessibility/scroll-window-horiz-sends-notification-expected.txt
@@ -0,0 +1,5 @@ +CONSOLE MESSAGE: line 28: Got notification on web area +This is a testharness.js-based test. +FAIL This test ensures that scrolling the window sends a notification. assert_equals: expected 500 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-contain/README.txt b/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-contain/README.txt new file mode 100644 index 0000000..73fecb3 --- /dev/null +++ b/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-contain/README.txt
@@ -0,0 +1,2 @@ +These tests are run with --enable-blink-features=LayoutNGGrid +The LayoutNG project is described here: http://goo.gl/1hwhfX
diff --git a/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-sizing/contain-intrinsic-size/README.txt b/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-sizing/contain-intrinsic-size/README.txt new file mode 100644 index 0000000..73fecb3 --- /dev/null +++ b/third_party/blink/web_tests/virtual/layout-ng-grid/external/wpt/css/css-sizing/contain-intrinsic-size/README.txt
@@ -0,0 +1,2 @@ +These tests are run with --enable-blink-features=LayoutNGGrid +The LayoutNG project is described here: http://goo.gl/1hwhfX
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt new file mode 100644 index 0000000..010886b --- /dev/null +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -0,0 +1,79 @@ +This is a testharness.js-based test. +Found 75 tests; 70 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS getStats succeeds +PASS Validating stats +PASS RTCRtpStreamStats's ssrc +PASS RTCRtpStreamStats's kind +PASS RTCRtpStreamStats's transportId +PASS RTCRtpStreamStats's codecId +PASS RTCReceivedRtpStreamStats's packetsReceived +PASS RTCReceivedRtpStreamStats's packetsLost +PASS RTCReceivedRtpStreamStats's jitter +FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false +PASS RTCReceivedRtpStreamStats's framesDropped +FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false +PASS RTCInboundRtpStreamStats's remoteId +PASS RTCInboundRtpStreamStats's framesDecoded +PASS RTCInboundRtpStreamStats's nackCount +PASS RTCInboundRtpStreamStats's framesReceived +PASS RTCInboundRtpStreamStats's bytesReceived +PASS RTCInboundRtpStreamStats's totalAudioEnergy +PASS RTCInboundRtpStreamStats's totalSamplesDuration +PASS RTCRemoteInboundRtpStreamStats's localId +PASS RTCRemoteInboundRtpStreamStats's roundTripTime +PASS RTCSentRtpStreamStats's packetsSent +PASS RTCSentRtpStreamStats's bytesSent +FAIL RTCOutboundRtpStreamStats's senderId assert_true: Is senderId present expected true got false +PASS RTCOutboundRtpStreamStats's remoteId +PASS RTCOutboundRtpStreamStats's framesEncoded +PASS RTCOutboundRtpStreamStats's nackCount +PASS RTCOutboundRtpStreamStats's framesSent +PASS RTCRemoteOutboundRtpStreamStats's localId +PASS RTCRemoteOutboundRtpStreamStats's remoteTimestamp +PASS RTCPeerConnectionStats's dataChannelsOpened +PASS RTCPeerConnectionStats's dataChannelsClosed +PASS RTCDataChannelStats's label +PASS RTCDataChannelStats's protocol +PASS RTCDataChannelStats's dataChannelIdentifier +PASS RTCDataChannelStats's state +PASS RTCDataChannelStats's messagesSent +PASS RTCDataChannelStats's bytesSent +PASS RTCDataChannelStats's messagesReceived +PASS RTCDataChannelStats's bytesReceived +PASS RTCMediaSourceStats's trackIdentifier +PASS RTCMediaSourceStats's kind +PASS RTCAudioSourceStats's totalAudioEnergy +PASS RTCAudioSourceStats's totalSamplesDuration +PASS RTCVideoSourceStats's width +PASS RTCVideoSourceStats's height +PASS RTCVideoSourceStats's framesPerSecond +FAIL RTCMediaHandlerStats's trackIdentifier assert_true: Is trackIdentifier present expected true got false +PASS RTCCodecStats's payloadType +PASS RTCCodecStats's mimeType +PASS RTCCodecStats's clockRate +PASS RTCCodecStats's channels +PASS RTCCodecStats's sdpFmtpLine +PASS RTCTransportStats's bytesSent +PASS RTCTransportStats's bytesReceived +PASS RTCTransportStats's selectedCandidatePairId +PASS RTCTransportStats's localCertificateId +PASS RTCTransportStats's remoteCertificateId +PASS RTCIceCandidatePairStats's transportId +PASS RTCIceCandidatePairStats's localCandidateId +PASS RTCIceCandidatePairStats's remoteCandidateId +PASS RTCIceCandidatePairStats's state +PASS RTCIceCandidatePairStats's nominated +PASS RTCIceCandidatePairStats's bytesSent +PASS RTCIceCandidatePairStats's bytesReceived +PASS RTCIceCandidatePairStats's totalRoundTripTime +PASS RTCIceCandidatePairStats's currentRoundTripTime +PASS RTCIceCandidateStats's address +PASS RTCIceCandidateStats's port +PASS RTCIceCandidateStats's protocol +PASS RTCIceCandidateStats's candidateType +FAIL RTCIceCandidateStats's url assert_true: Is url present expected true got false +PASS RTCCertificateStats's fingerprint +PASS RTCCertificateStats's fingerprintAlgorithm +PASS RTCCertificateStats's base64Certificate +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt new file mode 100644 index 0000000..585d803 --- /dev/null +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: stable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 +PASS setLocalDescription(pranswer) should succeed +PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer +PASS setLocalDescription(answer) from have-local-pranswer state should succeed +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/message-boxes.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/message-boxes.html index 4ff0584..149df5d 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/resources/message-boxes.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/message-boxes.html
@@ -1,34 +1,47 @@ <!DOCTYPE html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="utils.js"></script> <script> - function runAlertTest() { window.alert('Hello! Preprendering!'); - bc.postMessage('no block'); + return 'no block'; } function runConfirmTest() { const result = window.confirm('Are you preprendering page?'); - bc.postMessage('the return value is ' + (result === true ? 'yes' : 'no')); + return 'the return value is ' + (result === true ? 'yes' : 'no'); } function runPromptTest() { - const result = window.prompt('Are you preprendering page?', 'the default value'); - bc.postMessage('the return value is ' + - (result === '' ? 'the empty string' : result)); + const result = window.prompt('Are you preprendering page?', + 'the default value'); + return 'the return value is ' + (result === '' ? 'the empty string' : result); } -const bc = new BroadcastChannel('prerender-channel'); -assert_true(document.prerendering); const params = new URLSearchParams(location.search); -if (params.has('alert')) - runAlertTest(); -else if (params.has('confirm')) - runConfirmTest(); -else if (params.has('prompt')) - runPromptTest(); +// The main test page (restriction-message-boxes.html) loads the +// initiator page, then the initiator page will prerender itself with the +// `prerendering` parameter. +const isPrerendering = params.has('prerendering'); -bc.close(); +if (isPrerendering) { + // Test web APIs on the pages. + const bc = new BroadcastChannel('prerender-channel'); + assert_true(document.prerendering); + if (params.has('alert')) { + bc.postMessage(runAlertTest()); + } else if (params.has('confirm')) + bc.postMessage(runConfirmTest()); + else if (params.has('prompt')) + bc.postMessage(runPromptTest()); + bc.close(); + window.close(); +} else { + // Initiator pages should prerender the prerendering page. + const url = new URL(document.URL); + url.searchParams.append('prerendering', ''); + startPrerendering(url); +} </script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/utils.js b/third_party/blink/web_tests/wpt_internal/prerender/resources/utils.js index fc04bd71..fb53e73 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/resources/utils.js +++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/utils.js
@@ -2,14 +2,15 @@ // Starts prerendering for `url`. function startPrerendering(url) { - // Adds <link rel=prerender> for the URL. - // TODO(https://crbug.com/1174978): <link rel=prerender> may not start - // prerendering for some reason (e.g., resource limit). Implement a WebDriver - // API to force prerendering. - const link = document.createElement('link'); - link.rel = 'prerender'; - link.href = url; - document.head.appendChild(link); + // Adds <script type="speculationrules"> and specifies a prerender candidate + // for the given URL. + // TODO(https://crbug.com/1174978): <script type="speculationrules"> may not + // start prerendering for some reason (e.g., resource limit). Implement a + // WebDriver API to force prerendering. + const script = document.createElement('script'); + script.type = 'speculationrules'; + script.text = `{"prerender": [{"source": "list", "urls": ["${url}"] }] }`; + document.head.appendChild(script); } // Reads the value specified by `key` from the key-value store on the server.
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/restriction-message-boxes.html b/third_party/blink/web_tests/wpt_internal/prerender/restriction-message-boxes.html index 106d8cd..1b3dbb1 100644 --- a/third_party/blink/web_tests/wpt_internal/prerender/restriction-message-boxes.html +++ b/third_party/blink/web_tests/wpt_internal/prerender/restriction-message-boxes.html
@@ -22,7 +22,8 @@ }); }); - startPrerendering(test_file); + // Open a new window to test the message box. + window.open(test_file, '_blank', 'noopener'); // Wait for the message from the prerendering page. assert_equals(await gotMessage, expectation);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html index ea5ce72..619aed0 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
@@ -433,6 +433,10 @@ <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:max_dynamic_buffers:*'> <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:max_resources_per_stage,in_bind_group_layout:*'> <meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:max_resources_per_stage,in_pipeline_layout:*'> +<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:basic_use_of_createComputePipeline:*'> +<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:shader_module_must_be_valid:*'> +<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:shader_module_stage_must_be_compute:*'> +<meta name=variant content='?q=webgpu:api,validation,createComputePipeline:enrty_point_name_must_match:*'> <meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:number_of_dynamic_buffers_exceeds_the_maximum_value:*'> <meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:number_of_bind_group_layouts_exceeds_the_maximum_value:*'> <meta name=variant content='?q=webgpu:api,validation,createRenderPipeline:basic_use_of_createRenderPipeline:*'>
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js index 94c65463..c903798 100644 --- a/third_party/closure_compiler/externs/automation.js +++ b/third_party/closure_compiler/externs/automation.js
@@ -145,7 +145,6 @@ ABBR: 'abbr', ALERT: 'alert', ALERT_DIALOG: 'alertDialog', - ANCHOR: 'anchor', APPLICATION: 'application', ARTICLE: 'article', AUDIO: 'audio',
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn index 26c8e06..b9c31a7 100644 --- a/third_party/harfbuzz-ng/BUILD.gn +++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -267,7 +267,14 @@ # TODO(https://crbug.com/949962): Remove once this is fixed upstream. "U_DISABLE_VERSION_SUFFIX=0", - # https:/crbug.com/1203071 + # Letting HarfBuzz enable warnings through pragmas can block compiler + # upgrades in situations where say a ToT compiler build adds a new + # stricter warning under -Wfoowarning-subgroup. HarfBuzz pragma-enables + # -Wfoowarning which default-enables -Wfoowarning-subgroup implicitly but + # HarfBuzz upstream is not yet clean of warnings produced for + # -Wfoowarning-subgroup. Hence disabling pragma warning control here. + # See also https:/crbug.com/1203071 + "HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR", "HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING", ]
diff --git a/third_party/wayland-protocols/BUILD.gn b/third_party/wayland-protocols/BUILD.gn index 1e55417b5..1f1202b9 100644 --- a/third_party/wayland-protocols/BUILD.gn +++ b/third_party/wayland-protocols/BUILD.gn
@@ -140,3 +140,7 @@ wayland_protocol("weston_test") { sources = [ "unstable/weston-test/weston-test.xml" ] } + +wayland_protocol("org_kde_kwin_idle") { + sources = [ "kde/idle/idle.xml" ] +}
diff --git a/third_party/wayland-protocols/kde/idle/README b/third_party/wayland-protocols/kde/idle/README new file mode 100644 index 0000000..673e3ce --- /dev/null +++ b/third_party/wayland-protocols/kde/idle/README
@@ -0,0 +1,13 @@ +KDE Idle Wayland protocol extension + +Maintainers: +Alexander Dunaev <adunaev@igalia.com> + +Additional resources: +https://wayland.app/protocols/kde-idle + +Source: +https://github.com/KDE/plasma-wayland-protocols/blob/master/src/protocols/idle.xml + +This protocol allows to query KDE Plasma desktop environment for the idle time, +and to get notifications about the system entering and leaving the idle status.
diff --git a/third_party/wayland-protocols/kde/idle/idle.xml b/third_party/wayland-protocols/kde/idle/idle.xml new file mode 100644 index 0000000..575c7eb --- /dev/null +++ b/third_party/wayland-protocols/kde/idle/idle.xml
@@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="idle"> + <copyright><![CDATA[ + SPDX-FileCopyrightText: 2015 Martin Gräßlin + + SPDX-License-Identifier: LGPL-2.1-or-later + ]]></copyright> + <interface name="org_kde_kwin_idle" version="1"> + <description summary="User idle time manager"> + This interface allows to monitor user idle time on a given seat. The interface + allows to register timers which trigger after no user activity was registered + on the seat for a given interval. It notifies when user activity resumes. + + This is useful for applications wanting to perform actions when the user is not + interacting with the system, e.g. chat applications setting the user as away, power + management features to dim screen, etc.. + </description> + <request name="get_idle_timeout"> + <arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/> + <arg name="seat" type="object" interface="wl_seat"/> + <arg name="timeout" type="uint" summary="The idle timeout in msec"/> + </request> + </interface> + <interface name="org_kde_kwin_idle_timeout" version="1"> + <request name="release" type="destructor"> + <description summary="release the timeout object"/> + </request> + <request name="simulate_user_activity"> + <description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/> + </request> + <event name="idle"> + <description summary="Triggered when there has not been any user activity in the requested idle time interval"/> + </event> + <event name="resumed"> + <description summary="Triggered on the first user activity after an idle event"/> + </event> + </interface> +</protocol>
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt index 0be1475..238be98d 100644 --- a/third_party/webgpu-cts/ts_sources.txt +++ b/third_party/webgpu-cts/ts_sources.txt
@@ -127,6 +127,7 @@ src/webgpu/api/validation/attachment_compatibility.spec.ts src/webgpu/api/validation/createBindGroup.spec.ts src/webgpu/api/validation/createBindGroupLayout.spec.ts +src/webgpu/api/validation/createComputePipeline.spec.ts src/webgpu/api/validation/createPipelineLayout.spec.ts src/webgpu/api/validation/createRenderPipeline.spec.ts src/webgpu/api/validation/createSampler.spec.ts
diff --git a/tools/android/modularization/loc/modularization_loc_stat.py b/tools/android/modularization/loc/modularization_loc_stat.py index 16c9668..f975a68 100755 --- a/tools/android/modularization/loc/modularization_loc_stat.py +++ b/tools/android/modularization/loc/modularization_loc_stat.py
@@ -15,12 +15,13 @@ import sys from collections import OrderedDict from collections import defaultdict -from typing import Tuple +from typing import List, Tuple # Output json keys KEY_LOC_MODULARIZED = 'loc_modularized' KEY_LOC_LEGACY = 'loc_legacy' -KEY_RANKINGS = 'rankings' +KEY_RANKINGS_MODULARIZED = 'rankings' +KEY_RANKINGS_LEGACY = 'rankings_legacy' KEY_START_DATE = 'start_date' KEY_END_DATE = 'end_date' @@ -86,7 +87,8 @@ print(f'\nSTDOUT: {e.stdout}', file=sys.stderr) raise - author_stat = defaultdict(int) + author_stat_m12n = defaultdict(int) + author_stat_legacy = defaultdict(int) total_m12n = 0 total_legacy = 0 prev_msg_len = 0 @@ -111,9 +113,10 @@ diff = int(added) if _is_m12n_path(path): total_m12n += diff - author_stat[author] += diff + author_stat_m12n[author] += diff elif _is_legacy_path(path): total_legacy += diff + author_stat_legacy[author] += diff msg = f'\rProcessing {commit_date} by {author}' if not quiet: _print_progress(msg, prev_msg_len) @@ -123,14 +126,17 @@ _print_progress('Processing complete', prev_msg_len) print('\n') - rankings = OrderedDict( - sorted(author_stat.items(), key=lambda x: x[1], reverse=True)) + rankings_modularized = OrderedDict( + sorted(author_stat_m12n.items(), key=lambda x: x[1], reverse=True)) + rankings_legacy = OrderedDict( + sorted(author_stat_legacy.items(), key=lambda x: x[1], reverse=True)) if json_format: return json.dumps({ KEY_LOC_MODULARIZED: total_m12n, KEY_LOC_LEGACY: total_legacy, - KEY_RANKINGS: rankings, + KEY_RANKINGS_MODULARIZED: rankings_modularized, + KEY_RANKINGS_LEGACY: rankings_legacy, KEY_START_DATE: start_date, KEY_END_DATE: end_date, }) @@ -139,24 +145,35 @@ total = total_m12n + total_legacy percentage = 100.0 * total_m12n / total if total > 0 else 0 output.append(f'# of lines added in modularized files: {total_m12n}') - output.append(f'# of lines added in legacy files: {total_legacy}') + output.append(f'# of lines added in non-modularized files: {total_legacy}') output.append(f'% of lines landing in modularized files: {percentage:2.2f}') - # Shows the top 50 contributors to modularized files. - output.append('\nTop contributors:') - if rankings: - output.append('No lines % author') - for rank, author in enumerate(list(rankings.keys())[:50], 1): - lines = rankings[author] - if lines == 0: - break - ratio = 100 * lines / total_m12n - output.append(f'{rank:2d} {lines:6d} {ratio:5.1f} {author}') - else: - output.append('...none found.') + # Shows the top 50 contributors in each category. + output.extend( + _print_ranking(rankings_modularized, total_m12n, + 'modules and components')) + output.extend( + _print_ranking(rankings_legacy, total_legacy, 'legacy and glue')) + return '\n'.join(output) +def _print_ranking(rankings: OrderedDict, total: int, label: str) -> List[str]: + if not rankings: + return [] + + output = [] + output.append(f'\nTop contributors ({label}):') + output.append('No lines % author') + for rank, author in enumerate(list(rankings.keys())[:50], 1): + lines = rankings[author] + if lines == 0: + break + ratio = 100 * lines / total + output.append(f'{rank:2d} {lines:6d} {ratio:5.1f} {author}') + return output + + def _is_m12n_path(path): for prefix in _M12N_DIRS: if path.startswith(prefix):
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index f738d30..2f9505d3 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -39,8 +39,8 @@ # https://chromium.googlesource.com/chromium/src/+/main/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. # This is the output of `git describe` and is usable as a commit-ish. -CLANG_REVISION = 'llvmorg-13-init-10392-gd3676d4b' -CLANG_SUB_REVISION = 2 +CLANG_REVISION = 'llvmorg-13-init-11649-g4d788fb8' +CLANG_SUB_REVISION = 1 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION) RELEASE_VERSION = '13.0.0'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a44bfcf..29cf4f68 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -45444,6 +45444,7 @@ <int value="-1650769314" label="enable-webgl2-compute-context"/> <int value="-1649778035" label="disable-clear-browsing-data-counters"/> <int value="-1648216169" label="NewOmniboxAnswerTypes:disabled"/> + <int value="-1647433421" label="use-passthrough-command-decoder"/> <int value="-1646016597" label="IsolatePrerenders:disabled"/> <int value="-1645071473" label="ChromeColors:disabled"/> <int value="-1644308778" label="WASAPIRawAudioCapture:disabled"/> @@ -45601,6 +45602,7 @@ <int value="-1520952503" label="SearchReadyOmnibox:enabled"/> <int value="-1520855274" label="PWAFullCodeCache:disabled"/> <int value="-1520645293" label="InterestFeedNoticeCardAutoDismiss:disabled"/> + <int value="-1520630395" label="DefaultPassthroughCommandDecoder:disabled"/> <int value="-1517518406" label="force-update-menu-type"/> <int value="-1515415104" label="top-document-isolation:disabled"/> <int value="-1514943439" label="ash-enable-swipe-to-close-in-overview-mode"/> @@ -47911,6 +47913,7 @@ <int value="463582989" label="CompositorThreadedScrollbarScrolling:disabled"/> <int value="464226051" label="CrOSComponent:enabled"/> <int value="464773709" label="OmniboxExperimentalSuggestScoring:enabled"/> + <int value="465600939" label="DefaultPassthroughCommandDecoder:enabled"/> <int value="466248382" label="disable-push-api-background-mode"/> <int value="468665559" label="TrilinearFiltering:disabled"/> <int value="468901900" label="AppStoreBillingDebug:disabled"/> @@ -66354,6 +66357,8 @@ <int value="12" label="Exceeding maximum number of migrations on write error"/> <int value="13" label="Path degrading before handshake confirmed"/> + <int value="14" label="Idle migration period exceeded"/> + <int value="15" label="Migration fails due to lack of connection ID"/> </enum> <enum name="QuicDisabledReason"> @@ -78165,6 +78170,8 @@ </enum> <enum name="TimeLimitPolicyType"> +<!-- App Time Limit does not cover blocked apps. --> + <int value="0" label="No Time Limit"/> <int value="1" label="Override Time Limit"/> <int value="2" label="Bed Time Limit"/>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml index e9ebfc8b..43607f8 100644 --- a/tools/metrics/histograms/histograms_xml/android/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -2462,6 +2462,27 @@ </summary> </histogram> +<histogram name="Android.Survey.DownloadAttemptsBeforeAccepted" units="units" + expires_after="2022-06-01"> + <owner>skym@chromium.org</owner> + <owner>wenyufu@chromium.org</owner> + <owner>clank-app-team@google.com</owner> + <summary> + The number of survey download request attempts that have been made before + the survey is accepted. Note: + + 1) The download attempt might not result in a survey download due to + different reasons (e.g. download request failed or network failure); 2) + Chrome may also successfully download the survey number of times in previous + sessions, but the surveys were not able to be shown for min amount of times. + In such scenario, the total number of attempts across all sessions will be + recorded; 3) If the number of allowed download attempts has been saturated + before the survey being accepted, nothing will be recorded. + + Recorded when a survey prompt is accepted. Android Only. + </summary> +</histogram> + <histogram name="Android.Survey.DownloadRequested" enum="BooleanRequested" expires_after="2021-06-01"> <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml index 5275658..7a7b825 100644 --- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -237,6 +237,9 @@ <histogram name="Extensions.Bindings.UpdateBindingsForContextTime" units="microseconds" expires_after="2021-01-31"> + <obsolete> + Code removed 2021/06. + </obsolete> <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -1080,7 +1083,9 @@ </histogram> <histogram name="Extensions.Events.DispatchToComponent" enum="ExtensionEvents" - expires_after="2021-06-01"> + expires_after="never"> +<!-- expires-never: Monitoring core extensions platform behavior. --> + <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -2543,7 +2548,9 @@ </histogram> <histogram name="Extensions.LoadOffStoreItems" units="Number of items" - expires_after="2021-06-01"> + expires_after="never"> +<!-- expires-never: Monitoring core extension usage. --> + <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -3414,7 +3421,9 @@ </histogram> <histogram name="Extensions.Toolbar.PinnedExtensionCount2" - units="pinned extensions" expires_after="2021-10-31"> + units="pinned extensions" expires_after="never"> +<!-- expires-never: Monitoring core user behavior with extensions. --> + <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary> @@ -3425,7 +3434,9 @@ </histogram> <histogram name="Extensions.Toolbar.PinnedExtensionPercentage3" units="%" - expires_after="2021-06-30"> + expires_after="never"> +<!-- expires-never: Monitoring core user behavior with extensions. --> + <owner>rdevlin.cronin@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml index 16c5ccb..5e22f14 100644 --- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -380,7 +380,11 @@ </histogram> <histogram name="GPU.DirectComposition.CompositionMode" - enum="DxgiFramePresentationMode" expires_after="2021-10-04"> + enum="DxgiFramePresentationMode" expires_after="M92"> + <obsolete> + Obsoleted after M92. Unused and expired. Replaced by + GPU.DirectComposition.CompositionMode2.VideoOrCanvas. + </obsolete> <owner>sunnyps@chromium.org</owner> <owner>zmo@chromium.org</owner> <summary> @@ -390,7 +394,12 @@ </histogram> <histogram name="GPU.DirectComposition.CompositionMode.MainBuffer" - enum="DxgiFramePresentationMode" expires_after="2021-10-17"> + enum="DxgiFramePresentationMode" expires_after="M92"> + <obsolete> + Obsoleted after M92. Unused and expired. Replaced by + GPU.DirectComposition.CompositionMode2.MainBuffer.FullDamage and + GPU.DirectComposition.CompositionMode2.MainBuffer.PartialDamage. + </obsolete> <owner>zmo@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -399,6 +408,30 @@ </summary> </histogram> +<histogram name="GPU.DirectComposition.CompositionMode2.MainBuffer.{Damage}" + enum="DxgiFramePresentationMode" expires_after="2021-12-31"> + <owner>zmo@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + How the Desktop Window Manager presented Chrome's main DirectComposition + layer to the screen using {Damage}. Only recorded on Windows. + </summary> + <token key="Damage"> + <variant name="FullDamage" summary="full damage"/> + <variant name="PartialDamage" summary="partial damage"/> + </token> +</histogram> + +<histogram name="GPU.DirectComposition.CompositionMode2.VideoOrCanvas" + enum="DxgiFramePresentationMode" expires_after="2021-12-31"> + <owner>sunnyps@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + How the Desktop Window Manager presented Chrome's DirectComposition layers + of video or canvas elements to the screen. Only recorded on Windows. + </summary> +</histogram> + <histogram name="GPU.DirectComposition.CreateSwapChainForComposition" enum="Hresult" expires_after="2021-10-04"> <owner>magchen@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 427e15cb..0ed9790d 100644 --- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -6544,6 +6544,9 @@ </histogram_suffixes> <histogram_suffixes name="ExtensionContextType" separator="."> + <obsolete> + Removed 2021/06. + </obsolete> <suffix name="BlessedExtensionContext" label="Blessed Extension Context"/> <suffix name="BlessedWebPageContext" label="Blessed Web Page Context"/> <suffix name="ContentScriptContext" label="Content Script Context"/> @@ -18431,6 +18434,7 @@ <affected-histogram name="SoftwareReporter.RunningTime"/> <affected-histogram name="SoftwareReporter.RunningTimeAccordingToChrome"/> <affected-histogram name="SoftwareReporter.RunningTimeRegistryError"/> + <affected-histogram name="SoftwareReporter.RunningTimeWithoutSleep"/> <affected-histogram name="SoftwareReporter.Step"/> </histogram_suffixes>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 594487b870..0165677 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -613,9 +613,10 @@ </histogram> <histogram name="AppBanners.BeforeInstallEvent" - enum="AppBannersBeforeInstallEvent" expires_after="2021-06-01"> + enum="AppBannersBeforeInstallEvent" expires_after="2022-06-01"> <owner>dominickn@chromium.org</owner> <owner>pjmclachlan@google.com</owner> + <owner>desktop-pwas-team@google.com</owner> <summary> App banners promote an application related to the current website, and are requested specifically through the current page's HTML. This stat tracks @@ -3539,6 +3540,18 @@ </summary> </histogram> +<histogram name="Conversions.RedirectInterceptedFrameDetached" enum="Boolean" + expires_after="M95"> + <owner>apaseltiner@chromium.org</owner> + <owner>johnidel@chromium.org</owner> + <owner>measurement-api-dev+metrics@google.com</owner> + <summary> + Measures how often conversions are not handled due to the frame being + detached. Recorded when an attribution trigger redirect is received. This is + recorded regardless of the Attribution Reporting API being enabled. + </summary> +</histogram> + <histogram name="Conversions.RegisteredConversionsPerPage" units="conversions" expires_after="2021-11-07"> <owner>johnidel@chromium.org</owner> @@ -5673,8 +5686,10 @@ <owner>cros-families-eng@google.com</owner> <summary> Records whether managed sites approved list and blocked list are enabled for - currently active Family Link user. Reports at the beginning of the first - active session daily. Ignores the reports during OOBE and sign out. + currently active Family Link user. Prior to M93, this metric was recorded at + the beginning of first active session daily. In M93, this metric is now also + recorded when manual hosts and manual urls policies are changed. Ignores the + reports during OOBE and sign out. </summary> </histogram> @@ -5767,7 +5782,10 @@ <summary> Records what time limit policy types are enabled for the currently active Family Link user. Enabling multiple policies would report multiple buckets - to UMA. Reports at the beginning of the first active session daily. + to UMA. Prior to M93, this metric was recorded at the beginning of first + active session daily. In M93, this metric is now also recorded when bed time + limit, daily limit, override time limit, apps time limit and web time limit + policies are changed. App time limits does not include blocked apps. </summary> </histogram> @@ -5820,9 +5838,10 @@ <owner>xiqiruan@chromium.org</owner> <owner>cros-families-eng@google.com</owner> <summary> - Records the web filter type for currently active Family Link user. Reports - at the beginning of the first active session daily. Ignores the reports - during OOBE and sign out. + Records the web filter type for currently active Family Link user. Prior to + M93, this metric was recorded at the beginning of first active session + daily. In M93, this metric is now also recorded when web filter type policy + changed. Ignores the reports during OOBE and sign out. </summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/software/histograms.xml b/tools/metrics/histograms/histograms_xml/software/histograms.xml index 04c4cf1c..a5c37b4 100644 --- a/tools/metrics/histograms/histograms_xml/software/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/software/histograms.xml
@@ -413,12 +413,26 @@ </histogram> <histogram name="SoftwareReporter.RunningTimeAccordingToChrome" units="ms" - expires_after="2021-07-21"> + expires_after="2022-01-21"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> - The amount of time it took for the software reporter to run as measured by - chrome. Logged just after the software reporter tool has finished. + The amount of time from the Software Reporter process launch to the time it + exits, in milliseconds. This includes time the computer was asleep or + hibernating. SoftwareReporter.RunningTimeWithoutSleep excludes those + periods. + </summary> +</histogram> + +<histogram name="SoftwareReporter.RunningTimeWithoutSleep" units="ms" + expires_after="2022-01-21"> + <owner>drubery@chromium.org</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <summary> + The amount of time from the Software Reporter process launch to the time it + exits, in milliseconds. This does not include time the computer was asleep + or hibernating. SoftwareReporter.RunningTimeAccordingToChrome includes those + periods. </summary> </histogram>
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn index 89363eb2..344de9f 100644 --- a/tools/perf/BUILD.gn +++ b/tools/perf/BUILD.gn
@@ -2,38 +2,31 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Keep in sync with group("perf_without_chrome"). group("perf") { testonly = true - deps = [ "//tools/perf/chrome_telemetry_build:telemetry_chrome_test" ] - data = [ - "//tools/perf/", - - # Field trial config - "//tools/variations/", - "//testing/variations/", - - # Field trial dependencies - "//tools/json_comment_eater/", - "//tools/json_to_struct/", - "//components/variations/service/generate_ui_string_overrider.py", - - # For blink_perf benchmarks. - "//third_party/blink/perf_tests/", - - # For smoothness.tough_canvas_cases - "//chrome/test/data/perf/", - - # For image_decoding.measurement - "//chrome/test/data/image_decoding/", - - # For Pylib used by VR tests - "//build/android/pylib/", + data_deps = [ + ":perf_without_chrome", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", ] +} - # Runs a script which generates the ad tagging ruleset. - if (!is_ios) { - data_deps = [ "//components/subresource_filter/tools:index_ruleset" ] +if (is_android) { + template("perf_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":perf_without_chrome", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + perf_android_template("perf${_target_suffix}") { + telemetry_target_suffix = _target_suffix + } } } @@ -50,11 +43,10 @@ } } -# Group for running benchmarks without building Chrome. Keep in sync with -# group("perf"). +# Group for running benchmarks without building Chrome. group("perf_without_chrome") { testonly = true - deps = [ + data_deps = [ "//tools/perf/chrome_telemetry_build:telemetry_chrome_test_without_chrome", ] @@ -83,15 +75,10 @@ "//build/android/pylib/", ] - data_deps = [] - # Runs a script which generates the ad tagging ruleset. if (!is_ios) { data_deps += [ "//components/subresource_filter/tools:index_ruleset" ] } - if (is_android) { - data_deps += [ "//chrome/android/webapk/shell_apk:maps_go_webapk" ] - } } # This group makes visible those targets in subdirectories that are not
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index 5d1b435..641183d 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -37,6 +37,9 @@ data = [] if (is_android) { + # TODO(crbug.com/1213269): Remove these APK dependencies and fully switch to + # the separate Android targets below once all Android uses of the old target + # have been cleaned up. data_deps += [ ":telemetry_weblayer_apks", "//android_webview:system_webview_apk", @@ -100,6 +103,52 @@ } } +# These telemetry_chrome_test_* targets exist to reduce the amount of data +# included in swarming isolates. Including a bunch of different versions of +# Chrome and their unstripped .so files that aren't actually used adds gigabytes +# of data to the isolate, which in turn adds a non-trivial amount of swarming +# overhead. A new one should be added each time a new type of APK is supported +# and its suffix added to android_browser_types.gni. +if (is_android) { + group("telemetry_chrome_test_android_chrome") { + testonly = true + + data_deps = [ + ":telemetry_chrome_test", + "//chrome/android:chrome_public_apk", + ] + } + + group("telemetry_chrome_test_android_monochrome") { + testonly = true + + data_deps = [ + ":telemetry_chrome_test", + "//chrome/android:monochrome_public_apk", + ] + } + + group("telemetry_chrome_test_android_weblayer") { + testonly = true + + data_deps = [ + ":telemetry_chrome_test", + ":telemetry_weblayer_apks", + ] + } + + group("telemetry_chrome_test_android_webview") { + testonly = true + + data_deps = [ + ":telemetry_chrome_test", + "//android_webview:system_webview_apk", + "//android_webview/test:webview_instrumentation_apk", + "//android_webview/tools/system_webview_shell:system_webview_shell_apk", + ] + } +} + group("telemetry_weblayer_apks") { testonly = true
diff --git a/tools/perf/chrome_telemetry_build/android_browser_types.gni b/tools/perf/chrome_telemetry_build/android_browser_types.gni new file mode 100644 index 0000000..cb5eb4c4 --- /dev/null +++ b/tools/perf/chrome_telemetry_build/android_browser_types.gni
@@ -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. + +telemetry_android_browser_target_suffixes = [ + "_android_chrome", + "_android_monochrome", + "_android_weblayer", + "_android_webview", +]
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn index be25033..9521351 100644 --- a/tools/perf/contrib/vr_benchmarks/BUILD.gn +++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -5,7 +5,7 @@ import("//chrome/browser/vr/features.gni") import("//device/vr/buildflags/buildflags.gni") -group("vr_perf_tests") { +group("vr_perf_tests_base") { testonly = true data = [ "./data/", @@ -26,8 +26,6 @@ ] data_deps = [ "//testing:run_perf_test" ] - deps = [ "//tools/perf:perf" ] - if (is_android) { data += [ "//chrome/android/shared_preference_files/test/", @@ -47,7 +45,35 @@ if (is_win) { if (enable_openxr) { - deps += [ "//device/vr:openxr_mock" ] + data_deps += [ "//device/vr:openxr_mock" ] + } + } +} + +group("vr_perf_tests") { + testonly = true + data_deps = [ + ":vr_perf_tests_base", + "//tools/perf:perf", + ] +} + +if (is_android) { + template("vr_perf_tests_android_template") { + forward_variables_from(invoker, [ "telemetry_target_suffix" ]) + group(target_name) { + testonly = true + data_deps = [ + ":vr_perf_tests_base", + "//tools/perf:perf${telemetry_target_suffix}", + ] + } + } + + import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") + foreach(_target_suffix, telemetry_android_browser_target_suffixes) { + vr_perf_tests_android_template("vr_perf_tests${_target_suffix}") { + telemetry_target_suffix = _target_suffix } } }
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index f0d07b53..c2f6891 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -9,8 +9,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/mac/bae8193de6c017394901163b7817157342914679/trace_processor_shell" }, "linux": { - "hash": "4f34e5d1f2413ba3a665c0c07229753fca005f6c", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/5d06d8b9235d81033914a28c91cd72f0ffb4820e/trace_processor_shell" + "hash": "e2b8f1b68d26e0aee99c97b35b56e9b2a3279343", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/ae2171b89cb3e49f73ff100fc1647a93048ca472/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/typescript/definitions/management.d.ts b/tools/typescript/definitions/management.d.ts new file mode 100644 index 0000000..efd4f07 --- /dev/null +++ b/tools/typescript/definitions/management.d.ts
@@ -0,0 +1,19 @@ +// 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. + +/** @fileoverview Definitions for chrome.bookmarkManagerPrivate API. */ +// TODO(crbug.com/1203307): Auto-generate this file. + +declare namespace chrome { + export namespace management { + export interface UninstallOptions { + showConfirmDialog?: boolean; + } + + export function uninstall( + id: string, options?: UninstallOptions, callback?: () => void): void; + export function setEnabled( + id: string, enabled: boolean, callback?: () => void): void; + } +}
diff --git a/tools/typescript/definitions/runtime.d.ts b/tools/typescript/definitions/runtime.d.ts new file mode 100644 index 0000000..6cccfc3a --- /dev/null +++ b/tools/typescript/definitions/runtime.d.ts
@@ -0,0 +1,14 @@ +// 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. + +/** @fileoverview Definitions for chrome.runtime API */ +// TODO(crbug.com/1203307): Auto-generate this file. + +declare namespace chrome { + export namespace runtime { + export let lastError: { + message?: string, + } | undefined; + } +}
diff --git a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm index a7df344..3eb8157 100644 --- a/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm +++ b/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
@@ -58,7 +58,7 @@ base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer; CVPixelBufferCreateWithIOSurface(nullptr, io_surface, nullptr, cv_pixel_buffer.InitializeInto()); - gl_image->InitializeWithCVPixelBuffer(cv_pixel_buffer, + gl_image->InitializeWithCVPixelBuffer(cv_pixel_buffer, 0, gfx::GenericSharedMemoryId(), format); } else { gl_image->Initialize(io_surface, 0, gfx::GenericSharedMemoryId(), format);
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc index 86eccc3..8d652c05 100644 --- a/ui/accessibility/ax_enum_util.cc +++ b/ui/accessibility/ax_enum_util.cc
@@ -146,8 +146,6 @@ return "alertDialog"; case ax::mojom::Role::kAlert: return "alert"; - case ax::mojom::Role::kAnchor: - return "anchor"; case ax::mojom::Role::kApplication: return "application"; case ax::mojom::Role::kArticle:
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom index f61d7e44..f695a6b 100644 --- a/ui/accessibility/ax_enums.mojom +++ b/ui/accessibility/ax_enums.mojom
@@ -106,7 +106,7 @@ // Web: this attribute is only used in web content. // // Native: this attribute is only used in native UI. -// Next value: 186 +// Next value: 185 [Extensible, Stable, Uuid="d258eb73-e0cc-490c-b881-80ee11d3fec2"] enum Role { // Used for role="none"/"presentation" -- ignored in platform tree. @@ -114,201 +114,200 @@ kAbbr = 1, kAlert = 2, kAlertDialog = 3, - kAnchor = 4, - kApplication = 5, - kArticle = 6, - kAudio = 7, - kBanner = 8, - kBlockquote = 9, - kButton = 10, - kCanvas = 11, - kCaption = 12, - kCaret = 13, - kCell = 14, - kCheckBox = 15, - kClient = 16, - kCode = 17, - kColorWell = 18, - kColumn = 19, - kColumnHeader = 20, - kComboBoxGrouping = 21, - kComboBoxMenuButton = 22, - kComplementary = 23, - kComment = 24, - kContentDeletion = 25, - kContentInsertion = 26, - kContentInfo = 27, - kDate = 28, - kDateTime = 29, - kDefinition = 30, - kDescriptionList = 31, - kDescriptionListDetail = 32, - kDescriptionListTerm = 33, - kDesktop = 34, // internal - kDetails = 35, - kDialog = 36, - kDirectory = 37, - kDisclosureTriangle = 38, + kApplication = 4, + kArticle = 5, + kAudio = 6, + kBanner = 7, + kBlockquote = 8, + kButton = 9, + kCanvas = 10, + kCaption = 11, + kCaret = 12, + kCell = 13, + kCheckBox = 14, + kClient = 15, + kCode = 16, + kColorWell = 17, + kColumn = 18, + kColumnHeader = 19, + kComboBoxGrouping = 20, + kComboBoxMenuButton = 21, + kComplementary = 22, + kComment = 23, + kContentDeletion = 24, + kContentInsertion = 25, + kContentInfo = 26, + kDate = 27, + kDateTime = 28, + kDefinition = 29, + kDescriptionList = 30, + kDescriptionListDetail = 31, + kDescriptionListTerm = 32, + kDesktop = 33, // internal + kDetails = 34, + kDialog = 35, + kDirectory = 36, + kDisclosureTriangle = 37, // -------------------------------------------------------------- // DPub Roles: // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table - kDocAbstract = 39, - kDocAcknowledgments = 40, - kDocAfterword = 41, - kDocAppendix = 42, - kDocBackLink = 43, - kDocBiblioEntry = 44, - kDocBibliography = 45, - kDocBiblioRef = 46, - kDocChapter = 47, - kDocColophon = 48, - kDocConclusion = 49, - kDocCover = 50, - kDocCredit = 51, - kDocCredits = 52, - kDocDedication = 53, - kDocEndnote = 54, - kDocEndnotes = 55, - kDocEpigraph = 56, - kDocEpilogue = 57, - kDocErrata = 58, - kDocExample = 59, - kDocFootnote = 60, - kDocForeword = 61, - kDocGlossary = 62, - kDocGlossRef = 63, - kDocIndex = 64, - kDocIntroduction = 65, - kDocNoteRef = 66, - kDocNotice = 67, - kDocPageBreak = 68, - kDocPageFooter = 69, - kDocPageHeader = 70, - kDocPageList = 71, - kDocPart = 72, - kDocPreface = 73, - kDocPrologue = 74, - kDocPullquote = 75, - kDocQna = 76, - kDocSubtitle = 77, - kDocTip = 78, - kDocToc = 79, + kDocAbstract = 38, + kDocAcknowledgments = 39, + kDocAfterword = 40, + kDocAppendix = 41, + kDocBackLink = 42, + kDocBiblioEntry = 43, + kDocBibliography = 44, + kDocBiblioRef = 45, + kDocChapter = 46, + kDocColophon = 47, + kDocConclusion = 48, + kDocCover = 49, + kDocCredit = 50, + kDocCredits = 51, + kDocDedication = 52, + kDocEndnote = 53, + kDocEndnotes = 54, + kDocEpigraph = 55, + kDocEpilogue = 56, + kDocErrata = 57, + kDocExample = 58, + kDocFootnote = 59, + kDocForeword = 60, + kDocGlossary = 61, + kDocGlossRef = 62, + kDocIndex = 63, + kDocIntroduction = 64, + kDocNoteRef = 65, + kDocNotice = 66, + kDocPageBreak = 67, + kDocPageFooter = 68, + kDocPageHeader = 69, + kDocPageList = 70, + kDocPart = 71, + kDocPreface = 72, + kDocPrologue = 73, + kDocPullquote = 74, + kDocQna = 75, + kDocSubtitle = 76, + kDocTip = 77, + kDocToc = 78, // End DPub roles. // -------------------------------------------------------------- - kDocument = 80, - kEmbeddedObject = 81, - kEmphasis = 82, - kFeed = 83, - kFigcaption = 84, - kFigure = 85, - kFooter = 86, - kFooterAsNonLandmark = 87, - kForm = 88, - kGenericContainer = 89, + kDocument = 79, + kEmbeddedObject = 80, + kEmphasis = 81, + kFeed = 82, + kFigcaption = 83, + kFigure = 84, + kFooter = 85, + kFooterAsNonLandmark = 86, + kForm = 87, + kGenericContainer = 88, // -------------------------------------------------------------- // ARIA Graphics module roles: // https://rawgit.com/w3c/graphics-aam/master/#mapping_role_table - kGraphicsDocument = 90, - kGraphicsObject = 91, - kGraphicsSymbol = 92, + kGraphicsDocument = 89, + kGraphicsObject = 90, + kGraphicsSymbol = 91, // End ARIA Graphics module roles. // -------------------------------------------------------------- - kGrid = 93, - kGroup = 94, - kHeader = 95, - kHeaderAsNonLandmark = 96, - kHeading = 97, - kIframe = 98, - kIframePresentational = 99, - kImage = 100, - kImeCandidate = 101, - kInlineTextBox = 102, - kInputTime = 103, - kKeyboard = 104, - kLabelText = 105, - kLayoutTable = 106, - kLayoutTableCell = 107, - kLayoutTableRow = 108, - kLegend = 109, - kLineBreak = 110, - kLink = 111, - kList = 112, - kListBox = 113, - kListBoxOption = 114, + kGrid = 92, + kGroup = 93, + kHeader = 94, + kHeaderAsNonLandmark = 95, + kHeading = 96, + kIframe = 97, + kIframePresentational = 98, + kImage = 99, + kImeCandidate = 100, + kInlineTextBox = 101, + kInputTime = 102, + kKeyboard = 103, + kLabelText = 104, + kLayoutTable = 105, + kLayoutTableCell = 106, + kLayoutTableRow = 107, + kLegend = 108, + kLineBreak = 109, + kLink = 110, + kList = 111, + kListBox = 112, + kListBoxOption = 113, // kListGrid behaves similar to an ARIA grid but is primarily used by // TableView and its subclasses, so that they could be exposed correctly on // certain platforms. - kListGrid = 115, // Native - kListItem = 116, - kListMarker = 117, - kLog = 118, - kMain = 119, - kMark = 120, - kMarquee = 121, - kMath = 122, - kMenu = 123, - kMenuBar = 124, - kMenuItem = 125, - kMenuItemCheckBox = 126, - kMenuItemRadio = 127, - kMenuListOption = 128, - kMenuListPopup = 129, - kMeter = 130, - kNavigation = 131, - kNote = 132, - kPane = 133, - kParagraph = 134, - kPdfActionableHighlight = 135, - kPdfRoot = 136, - kPluginObject = 137, - kPopUpButton = 138, - kPortal = 139, - kPre = 140, - kProgressIndicator = 141, - kRadioButton = 142, - kRadioGroup = 143, - kRegion = 144, - kRootWebArea = 145, - kRow = 146, - kRowGroup = 147, - kRowHeader = 148, - kRuby = 149, - kRubyAnnotation = 150, - kScrollBar = 151, - kScrollView = 152, - kSearch = 153, - kSearchBox = 154, - kSection = 155, - kSlider = 156, - kSpinButton = 157, - kSplitter = 158, - kStaticText = 159, - kStatus = 160, - kStrong = 161, - kSuggestion = 162, - kSvgRoot = 163, - kSwitch = 164, - kTab = 165, - kTabList = 166, - kTabPanel = 167, - kTable = 168, - kTableHeaderContainer = 169, - kTerm = 170, - kTextField = 171, - kTextFieldWithComboBox = 172, - kTime = 173, - kTimer = 174, - kTitleBar = 175, - kToggleButton = 176, - kToolbar = 177, - kTooltip = 178, - kTree = 179, - kTreeGrid = 180, - kTreeItem = 181, - kUnknown = 182, - kVideo = 183, - kWebView = 184, - kWindow = 185, + kListGrid = 114, // Native + kListItem = 115, + kListMarker = 116, + kLog = 117, + kMain = 118, + kMark = 119, + kMarquee = 120, + kMath = 121, + kMenu = 122, + kMenuBar = 123, + kMenuItem = 124, + kMenuItemCheckBox = 125, + kMenuItemRadio = 126, + kMenuListOption = 127, + kMenuListPopup = 128, + kMeter = 129, + kNavigation = 130, + kNote = 131, + kPane = 132, + kParagraph = 133, + kPdfActionableHighlight = 134, + kPdfRoot = 135, + kPluginObject = 136, + kPopUpButton = 137, + kPortal = 138, + kPre = 139, + kProgressIndicator = 140, + kRadioButton = 141, + kRadioGroup = 142, + kRegion = 143, + kRootWebArea = 144, + kRow = 145, + kRowGroup = 146, + kRowHeader = 147, + kRuby = 148, + kRubyAnnotation = 149, + kScrollBar = 150, + kScrollView = 151, + kSearch = 152, + kSearchBox = 153, + kSection = 154, + kSlider = 155, + kSpinButton = 156, + kSplitter = 157, + kStaticText = 158, + kStatus = 159, + kStrong = 160, + kSuggestion = 161, + kSvgRoot = 162, + kSwitch = 163, + kTab = 164, + kTabList = 165, + kTabPanel = 166, + kTable = 167, + kTableHeaderContainer = 168, + kTerm = 169, + kTextField = 170, + kTextFieldWithComboBox = 171, + kTime = 172, + kTimer = 173, + kTitleBar = 174, + kToggleButton = 175, + kToolbar = 176, + kTooltip = 177, + kTree = 178, + kTreeGrid = 179, + kTreeItem = 180, + kUnknown = 181, + kVideo = 182, + kWebView = 183, + kWindow = 184, }; // Next value: 19
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index 8017d30..bb3af12 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -2390,10 +2390,8 @@ // AtkObject. It is indeed implemented by actual web hyperlinks, but also by // objects that will become embedded objects in ATK hypertext, so the name is // a bit of a misnomer from the ATK API. - if (IsLink(data.role) || data.role == ax::mojom::Role::kAnchor || - !ui::IsText(data.role)) { + if (IsLink(data.role) || !ui::IsText(data.role)) interface_mask.Add(ImplementedAtkInterfaces::Value::kHyperlink); - } if (data.role == ax::mojom::Role::kWindow) interface_mask.Add(ImplementedAtkInterfaces::Value::kWindow); @@ -2642,8 +2640,6 @@ return ATK_ROLE_NOTIFICATION; case ax::mojom::Role::kAlertDialog: return ATK_ROLE_ALERT; - case ax::mojom::Role::kAnchor: - return ATK_ROLE_LINK; case ax::mojom::Role::kComment: case ax::mojom::Role::kSuggestion: return ATK_ROLE_SECTION;
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index 22078bc..115f964 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -42,7 +42,6 @@ {ax::mojom::Role::kAbbr, NSAccessibilityGroupRole}, {ax::mojom::Role::kAlert, NSAccessibilityGroupRole}, {ax::mojom::Role::kAlertDialog, NSAccessibilityGroupRole}, - {ax::mojom::Role::kAnchor, NSAccessibilityGroupRole}, {ax::mojom::Role::kApplication, NSAccessibilityGroupRole}, {ax::mojom::Role::kArticle, NSAccessibilityGroupRole}, {ax::mojom::Role::kAudio, NSAccessibilityGroupRole},
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index d62db41..8de0faf 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -5280,9 +5280,6 @@ case ax::mojom::Role::kAlertDialog: return ROLE_SYSTEM_DIALOG; - case ax::mojom::Role::kAnchor: - return ROLE_SYSTEM_LINK; - case ax::mojom::Role::kComment: case ax::mojom::Role::kSuggestion: return ROLE_SYSTEM_GROUPING; @@ -6098,9 +6095,6 @@ // |ax::mojom::Role::kAlertDialog| yet. return L"alert"; - case ax::mojom::Role::kAnchor: - return L"link"; - case ax::mojom::Role::kComment: case ax::mojom::Role::kSuggestion: return L"group"; @@ -6768,9 +6762,6 @@ // |ax::mojom::Role::kAlertDialog| yet. return UIA_TextControlTypeId; - case ax::mojom::Role::kAnchor: - return UIA_HyperlinkControlTypeId; - case ax::mojom::Role::kComment: case ax::mojom::Role::kSuggestion: return UIA_GroupControlTypeId;
diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc index c6799bf..382918f 100644 --- a/ui/base/x/selection_utils.cc +++ b/ui/base/x/selection_utils.cc
@@ -22,25 +22,21 @@ namespace ui { std::vector<x11::Atom> GetTextAtomsFrom() { - std::vector<x11::Atom> atoms; - atoms.push_back(x11::GetAtom(kMimeTypeLinuxUtf8String)); - atoms.push_back(x11::GetAtom(kMimeTypeLinuxString)); - atoms.push_back(x11::GetAtom(kMimeTypeLinuxText)); - atoms.push_back(x11::GetAtom(kMimeTypeText)); - atoms.push_back(x11::GetAtom(kMimeTypeTextUtf8)); + static const std::vector<x11::Atom> atoms = { + x11::GetAtom(kMimeTypeLinuxUtf8String), + x11::GetAtom(kMimeTypeLinuxString), x11::GetAtom(kMimeTypeLinuxText), + x11::GetAtom(kMimeTypeText), x11::GetAtom(kMimeTypeTextUtf8)}; return atoms; } std::vector<x11::Atom> GetURLAtomsFrom() { - std::vector<x11::Atom> atoms; - atoms.push_back(x11::GetAtom(kMimeTypeURIList)); - atoms.push_back(x11::GetAtom(kMimeTypeMozillaURL)); + static const std::vector<x11::Atom> atoms = { + x11::GetAtom(kMimeTypeURIList), x11::GetAtom(kMimeTypeMozillaURL)}; return atoms; } std::vector<x11::Atom> GetURIListAtomsFrom() { - std::vector<x11::Atom> atoms; - atoms.push_back(x11::GetAtom(kMimeTypeURIList)); + static const std::vector<x11::Atom> atoms = {x11::GetAtom(kMimeTypeURIList)}; return atoms; }
diff --git a/ui/base/x/x11_clipboard_helper.cc b/ui/base/x/x11_clipboard_helper.cc index b6d23a1..34433517 100644 --- a/ui/base/x/x11_clipboard_helper.cc +++ b/ui/base/x/x11_clipboard_helper.cc
@@ -122,7 +122,7 @@ bool ContainsText() const { for (const auto& atom : GetTextAtomsFrom()) { - if (ContainsAtom(atom)) + if (base::Contains(target_list_, atom)) return true; } return false; @@ -130,10 +130,6 @@ bool ContainsFormat(const ClipboardFormatType& format_type) const { x11::Atom atom = x11::GetAtom(format_type.GetName().c_str()); - return ContainsAtom(atom); - } - - bool ContainsAtom(x11::Atom atom) const { return base::Contains(target_list_, atom); }
diff --git a/ui/gl/direct_composition_child_surface_win.cc b/ui/gl/direct_composition_child_surface_win.cc index d8380cd7..04ec80c8 100644 --- a/ui/gl/direct_composition_child_surface_win.cc +++ b/ui/gl/direct_composition_child_surface_win.cc
@@ -53,6 +53,10 @@ bool g_direct_composition_swap_chain_failed = false; +// If damage_rect / full_chrome_rect >= kForceFullDamageThreshold, present +// the swap chain with full damage. +float kForceFullDamageThreshold = 0.6f; + bool SupportsLowLatencyPresentation() { return base::FeatureList::IsEnabled( features::kDirectCompositionLowLatencyPresentation); @@ -74,11 +78,13 @@ VSyncCallback vsync_callback, bool use_angle_texture_offset, size_t max_pending_frames, - bool force_full_damage) + bool force_full_damage, + bool force_full_damage_always) : vsync_callback_(std::move(vsync_callback)), use_angle_texture_offset_(use_angle_texture_offset), max_pending_frames_(max_pending_frames), force_full_damage_(force_full_damage), + force_full_damage_always_(force_full_damage_always), vsync_thread_(VSyncThreadWin::GetInstance()), task_runner_(base::ThreadTaskRunnerHandle::Get()) {} @@ -154,10 +160,22 @@ first_swap_ || !vsync_enabled_ || use_swap_chain_tearing ? 0 : 1; UINT flags = use_swap_chain_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0; - TRACE_EVENT2("gpu", "DirectCompositionChildSurfaceWin::PresentSwapChain", - "interval", interval, "dirty_rect", - force_full_damage_ ? "full_damage" : swap_rect_.ToString()); + bool actually_force_full_damage = false; if (force_full_damage_) { + if (force_full_damage_always_) { + actually_force_full_damage = true; + } else { + float percentage = swap_rect_.size().GetArea(); + percentage /= size_.GetArea(); + if (percentage >= kForceFullDamageThreshold) + actually_force_full_damage = true; + } + } + TRACE_EVENT2( + "gpu", "DirectCompositionChildSurfaceWin::PresentSwapChain", + "interval", interval, "dirty_rect", + actually_force_full_damage ? "full_damage" : swap_rect_.ToString()); + if (actually_force_full_damage) { hr = swap_chain_->Present(interval, flags); } else { DXGI_PRESENT_PARAMETERS params = {}; @@ -174,7 +192,7 @@ } Microsoft::WRL::ComPtr<IDXGISwapChainMedia> swap_chain_media; - if (SUCCEEDED(swap_chain_.As(&swap_chain_media))) { + if (force_full_damage_ && SUCCEEDED(swap_chain_.As(&swap_chain_media))) { DXGI_FRAME_STATISTICS_MEDIA stats = {}; // GetFrameStatisticsMedia fails with // DXGI_ERROR_FRAME_STATISTICS_DISJOINT sometimes, which means an @@ -184,9 +202,16 @@ // Waiting for the DXGI adapter to finish presenting before calling // the function doesn't get rid of the failure. if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) { - base::UmaHistogramSparse( - "GPU.DirectComposition.CompositionMode.MainBuffer", - stats.CompositionMode); + if (actually_force_full_damage) { + base::UmaHistogramSparse( + "GPU.DirectComposition.CompositionMode2.MainBuffer.FullDamage", + stats.CompositionMode); + } else { + base::UmaHistogramSparse( + "GPU.DirectComposition.CompositionMode2.MainBuffer." + "PartialDamage", + stats.CompositionMode); + } } }
diff --git a/ui/gl/direct_composition_child_surface_win.h b/ui/gl/direct_composition_child_surface_win.h index b17ea4e..9240ae2 100644 --- a/ui/gl/direct_composition_child_surface_win.h +++ b/ui/gl/direct_composition_child_surface_win.h
@@ -34,7 +34,8 @@ DirectCompositionChildSurfaceWin(VSyncCallback vsync_callback, bool use_angle_texture_offset, size_t max_pending_frames, - bool force_full_damage); + bool force_full_damage, + bool force_full_damage_always); // GLSurfaceEGL implementation. bool Initialize(GLSurfaceFormat format) override; @@ -142,6 +143,7 @@ const bool use_angle_texture_offset_; const size_t max_pending_frames_; const bool force_full_damage_; + const bool force_full_damage_always_; VSyncThreadWin* const vsync_thread_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc index 3828639..3f9a84c 100644 --- a/ui/gl/direct_composition_surface_win.cc +++ b/ui/gl/direct_composition_surface_win.cc
@@ -394,7 +394,8 @@ std::move(vsync_callback), settings.use_angle_texture_offset, settings.max_pending_frames, - settings.force_root_surface_full_damage)), + settings.force_root_surface_full_damage, + settings.force_root_surface_full_damage_always)), layer_tree_( std::make_unique<DCLayerTree>(settings.disable_nv12_dynamic_textures, settings.disable_vp_scaling)) {
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h index 305850e..b99c7adc 100644 --- a/ui/gl/direct_composition_surface_win.h +++ b/ui/gl/direct_composition_surface_win.h
@@ -44,6 +44,7 @@ size_t max_pending_frames = 2; bool use_angle_texture_offset = false; bool force_root_surface_full_damage = false; + bool force_root_surface_full_damage_always = false; }; DirectCompositionSurfaceWin(
diff --git a/ui/gl/gl_image_io_surface.h b/ui/gl/gl_image_io_surface.h index 16c7594..f37f784 100644 --- a/ui/gl/gl_image_io_surface.h +++ b/ui/gl/gl_image_io_surface.h
@@ -46,6 +46,7 @@ // initialization will ensure that the CVPixelBuffer be retained for the // lifetime of the GLImage. bool InitializeWithCVPixelBuffer(CVPixelBufferRef cv_pixel_buffer, + uint32_t io_surface_plane, gfx::GenericSharedMemoryId io_surface_id, gfx::BufferFormat format);
diff --git a/ui/gl/gl_image_io_surface.mm b/ui/gl/gl_image_io_surface.mm index 8fa7729..321f866 100644 --- a/ui/gl/gl_image_io_surface.mm +++ b/ui/gl/gl_image_io_surface.mm
@@ -222,10 +222,10 @@ bool GLImageIOSurface::InitializeWithCVPixelBuffer( CVPixelBufferRef cv_pixel_buffer, + uint32_t io_surface_plane, gfx::GenericSharedMemoryId io_surface_id, gfx::BufferFormat format) { IOSurfaceRef io_surface = CVPixelBufferGetIOSurface(cv_pixel_buffer); - const uint32_t io_surface_plane = 0; if (!io_surface) { LOG(ERROR) << "Can't init GLImage from CVPixelBuffer with no IOSurface"; return false;
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc index 00cbf63..a7ade89 100644 --- a/ui/gl/swap_chain_presenter.cc +++ b/ui/gl/swap_chain_presenter.cc
@@ -1136,8 +1136,9 @@ HRESULT hr = swap_chain_media->GetFrameStatisticsMedia(&stats); int mode = -1; if (SUCCEEDED(hr)) { - base::UmaHistogramSparse("GPU.DirectComposition.CompositionMode", - stats.CompositionMode); + base::UmaHistogramSparse( + "GPU.DirectComposition.CompositionMode2.VideoOrCanvas", + stats.CompositionMode); if (frame_rate_ != 0) { // [1ms, 10s] covers the fps between [0.1hz, 1000hz]. base::UmaHistogramTimes("GPU.DirectComposition.ApprovedPresentDuration",
diff --git a/ui/ozone/platform/scenic/scenic_screen.cc b/ui/ozone/platform/scenic/scenic_screen.cc index 461c46f6..350dc0a 100644 --- a/ui/ozone/platform/scenic/scenic_screen.cc +++ b/ui/ozone/platform/scenic/scenic_screen.cc
@@ -49,25 +49,6 @@ display_it->set_bounds(bounds); } -void ScenicScreen::OnWindowMetrics(int32_t window_id, - float device_pixel_ratio) { - if (display::Display::HasForceDeviceScaleFactor()) - return; - - auto display_it = std::find_if(displays_.begin(), displays_.end(), - [window_id](display::Display& display) { - return display.id() == window_id; - }); - DCHECK(display_it != displays_.end()); - - display_it->set_device_scale_factor(device_pixel_ratio); - for (auto& observer : observers_) { - observer.OnDisplayMetricsChanged( - *display_it, - display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR); - } -} - base::WeakPtr<ScenicScreen> ScenicScreen::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
diff --git a/ui/ozone/platform/scenic/scenic_screen.h b/ui/ozone/platform/scenic/scenic_screen.h index b55e4ba..c6470ae 100644 --- a/ui/ozone/platform/scenic/scenic_screen.h +++ b/ui/ozone/platform/scenic/scenic_screen.h
@@ -24,7 +24,6 @@ // Processes window state change events for the ScenicWindow |window_id_|. void OnWindowAdded(int32_t window_id); void OnWindowRemoved(int32_t window_id); - void OnWindowMetrics(int32_t window_id, float device_pixel_ratio); void OnWindowBoundsChanged(int32_t window_id, gfx::Rect bounds); base::WeakPtr<ScenicScreen> GetWeakPtr();
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc index fb2806f..4b371df 100644 --- a/ui/ozone/platform/scenic/scenic_window.cc +++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -336,10 +336,6 @@ void ScenicWindow::OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics) { device_pixel_ratio_ = std::max(metrics.scale_x, metrics.scale_y); - ScenicScreen* screen = manager_->screen(); - if (screen) - screen->OnWindowMetrics(window_id_, device_pixel_ratio_); - if (view_properties_) UpdateSize(); }
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h index f5538eee..6d674ff4 100644 --- a/ui/ozone/platform/scenic/scenic_window.h +++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -144,8 +144,11 @@ std::unique_ptr<scenic::ViewHolder> surface_view_holder_; - // The ratio used for translating device-independent coordinates to absolute - // pixel coordinates. + // The scale between logical pixels and physical pixels, set based on the + // fuchsia::ui::gfx::Metrics event. It's used to calculate dimensions of the + // view in physical pixels in UpdateSize(). This value doesn't affect the + // device_scale_factor reported by ScenicScreen for the corresponding display + // (currently always 1.0, see crbug.com/1215330). float device_pixel_ratio_ = 0.f; // Current view size in DIPs.
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn index 98c74c3..321e719 100644 --- a/ui/ozone/platform/wayland/BUILD.gn +++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -52,6 +52,8 @@ "host/gtk_shell1.h", "host/gtk_surface1.cc", "host/gtk_surface1.h", + "host/org_kde_kwin_idle.cc", + "host/org_kde_kwin_idle.h", "host/shell_object_factory.cc", "host/shell_object_factory.h", "host/shell_popup_wrapper.cc", @@ -191,6 +193,7 @@ "//third_party/wayland-protocols:keyboard_extension_protocol", "//third_party/wayland-protocols:linux_dmabuf_protocol", "//third_party/wayland-protocols:linux_explicit_synchronization_protocol", + "//third_party/wayland-protocols:org_kde_kwin_idle", "//third_party/wayland-protocols:pointer_gestures_protocol", "//third_party/wayland-protocols:presentation_time_protocol", "//third_party/wayland-protocols:primary_selection_protocol",
diff --git a/ui/ozone/platform/wayland/common/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc index 5f63eb03..7b2139b 100644 --- a/ui/ozone/platform/wayland/common/wayland_object.cc +++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -9,6 +9,7 @@ #include <extended-drag-unstable-v1-client-protocol.h> #include <gtk-primary-selection-client-protocol.h> #include <gtk-shell-client-protocol.h> +#include <idle-client-protocol.h> #include <keyboard-extension-unstable-v1-client-protocol.h> #include <linux-dmabuf-unstable-v1-client-protocol.h> #include <linux-explicit-synchronization-unstable-v1-client-protocol.h> @@ -107,6 +108,16 @@ void (*ObjectTraits<gtk_surface1>::deleter)(gtk_surface1*) = >k_surface1_destroy; +const wl_interface* ObjectTraits<org_kde_kwin_idle>::interface = + &org_kde_kwin_idle_interface; +void (*ObjectTraits<org_kde_kwin_idle>::deleter)(org_kde_kwin_idle*) = + &org_kde_kwin_idle_destroy; + +const wl_interface* ObjectTraits<org_kde_kwin_idle_timeout>::interface = + &org_kde_kwin_idle_timeout_interface; +void (*ObjectTraits<org_kde_kwin_idle_timeout>::deleter)( + org_kde_kwin_idle_timeout*) = &org_kde_kwin_idle_timeout_destroy; + const wl_interface* ObjectTraits<zwp_primary_selection_device_manager_v1>::interface = &zwp_primary_selection_device_manager_v1_interface;
diff --git a/ui/ozone/platform/wayland/common/wayland_object.h b/ui/ozone/platform/wayland/common/wayland_object.h index ef805db..85001fb 100644 --- a/ui/ozone/platform/wayland/common/wayland_object.h +++ b/ui/ozone/platform/wayland/common/wayland_object.h
@@ -15,6 +15,8 @@ struct gtk_primary_selection_source; struct gtk_shell1; struct gtk_surface1; +struct org_kde_kwin_idle; +struct org_kde_kwin_idle_timeout; struct zwp_primary_selection_device_v1; struct zwp_primary_selection_device_manager_v1; struct zwp_primary_selection_offer_v1; @@ -131,6 +133,18 @@ }; template <> +struct ObjectTraits<org_kde_kwin_idle> { + static const wl_interface* interface; + static void (*deleter)(org_kde_kwin_idle*); +}; + +template <> +struct ObjectTraits<org_kde_kwin_idle_timeout> { + static const wl_interface* interface; + static void (*deleter)(org_kde_kwin_idle_timeout*); +}; + +template <> struct ObjectTraits<zwp_primary_selection_device_manager_v1> { static const wl_interface* interface; static void (*deleter)(zwp_primary_selection_device_manager_v1*);
diff --git a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc new file mode 100644 index 0000000..88857f43 --- /dev/null +++ b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.cc
@@ -0,0 +1,97 @@ +// 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 "ui/ozone/platform/wayland/host/org_kde_kwin_idle.h" + +#include <idle-client-protocol.h> + +#include "ui/ozone/platform/wayland/host/wayland_connection.h" + +namespace ui { + +namespace { + +// After the system has gone idle, it will wait for this time before notifying +// us. This reduces "jitter" of the idle/active state, but also adds some lag +// in responsiveness: when we are finally notified that the idle state has come, +// it is already there for kIdleThresholdMs milliseconds. +constexpr uint64_t kIdleThresholdMs = 5000; + +} // namespace + +// Wraps the actual handling of system notifications about the idle state. +class OrgKdeKwinIdle::Timeout { + public: + explicit Timeout(org_kde_kwin_idle_timeout* timeout); + Timeout(const Timeout&) = delete; + Timeout& operator=(const Timeout&) = delete; + ~Timeout(); + + // Returns the idle time. + base::TimeDelta GetIdleTime() const; + + private: + static void Idle(void* data, + struct org_kde_kwin_idle_timeout* org_kde_kwin_idle_timeout); + static void Resumed( + void* data, + struct org_kde_kwin_idle_timeout* org_kde_kwin_idle_timeout); + + wl::Object<org_kde_kwin_idle_timeout> timeout_; + + // Time when the system went into idle state. + base::Time idle_timestamp_; +}; + +OrgKdeKwinIdle::OrgKdeKwinIdle(org_kde_kwin_idle* idle, + WaylandConnection* connection) + : idle_(idle), connection_(connection) {} + +OrgKdeKwinIdle::~OrgKdeKwinIdle() = default; + +absl::optional<base::TimeDelta> OrgKdeKwinIdle::GetIdleTime() const { + if (!connection_->seat()) + return absl::nullopt; + + if (!idle_timeout_) { + idle_timeout_ = + std::make_unique<Timeout>(org_kde_kwin_idle_get_idle_timeout( + idle_.get(), connection_->seat(), kIdleThresholdMs)); + } + return idle_timeout_->GetIdleTime(); +} + +OrgKdeKwinIdle::Timeout::Timeout(org_kde_kwin_idle_timeout* timeout) + : timeout_(timeout) { + static const struct org_kde_kwin_idle_timeout_listener kTimeoutListener = { + OrgKdeKwinIdle::Timeout::Idle, OrgKdeKwinIdle::Timeout::Resumed}; + org_kde_kwin_idle_timeout_add_listener(timeout, &kTimeoutListener, this); +} + +OrgKdeKwinIdle::Timeout::~Timeout() = default; + +base::TimeDelta OrgKdeKwinIdle::Timeout::GetIdleTime() const { + if (idle_timestamp_.is_null()) + return base::TimeDelta::FromSeconds(0); + return base::Time::Now() - idle_timestamp_; +} + +// static +void OrgKdeKwinIdle::Timeout::Idle( + void* data, + struct org_kde_kwin_idle_timeout* org_kde_kwin_idle_timeout) { + auto* self = static_cast<OrgKdeKwinIdle::Timeout*>(data); + self->idle_timestamp_ = + base::Time::Now() - base::TimeDelta::FromMicroseconds(kIdleThresholdMs); +} + +// static +void OrgKdeKwinIdle::Timeout::Resumed( + void* data, + struct org_kde_kwin_idle_timeout* org_kde_kwin_idle_timeout) { + auto* self = static_cast<OrgKdeKwinIdle::Timeout*>(data); + self->idle_timestamp_ = {}; +} + +} // namespace ui
diff --git a/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h new file mode 100644 index 0000000..fd300abf --- /dev/null +++ b/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h
@@ -0,0 +1,43 @@ +// 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 UI_OZONE_PLATFORM_WAYLAND_HOST_ORG_KDE_KWIN_IDLE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_ORG_KDE_KWIN_IDLE_H_ + +#include <memory> + +#include "base/time/time.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" + +namespace ui { + +class WaylandConnection; + +// Wraps the KDE Wayland user idle time manager, which is provided via +// org_kde_kwin_idle interface. +class OrgKdeKwinIdle { + public: + OrgKdeKwinIdle(org_kde_kwin_idle* idle, WaylandConnection* connection); + OrgKdeKwinIdle(const OrgKdeKwinIdle&) = delete; + OrgKdeKwinIdle& operator=(const OrgKdeKwinIdle&) = delete; + ~OrgKdeKwinIdle(); + + // Returns the idle time if querying it is possible, absl::nullopt otherwise. + absl::optional<base::TimeDelta> GetIdleTime() const; + + private: + class Timeout; + + // Wayland object wrapped by this class. + wl::Object<org_kde_kwin_idle> idle_; + // The actual idle timeout connection point. + mutable std::unique_ptr<Timeout> idle_timeout_; + + WaylandConnection* const connection_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ORG_KDE_KWIN_IDLE_H_
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc index 9e03a64..04425c1 100644 --- a/ui/ozone/platform/wayland/host/wayland_connection.cc +++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -27,6 +27,7 @@ #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h" #include "ui/ozone/platform/wayland/host/gtk_shell1.h" +#include "ui/ozone/platform/wayland/host/org_kde_kwin_idle.h" #include "ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" #include "ui/ozone/platform/wayland/host/wayland_clipboard.h" @@ -94,6 +95,8 @@ constexpr uint32_t kMinGtkShell1Version = 3; constexpr uint32_t kMaxGtkShell1Version = 4; +constexpr uint32_t kMaxOrgKdeKwinIdleVersion = 1; + int64_t ConvertTimespecToMicros(const struct timespec& ts) { // On 32-bit systems, the calculation cannot overflow int64_t. // 2**32 * 1000000 + 2**64 / 1000 < 2**63 @@ -651,6 +654,16 @@ LOG(ERROR) << "Failed to bind to zcr_extended_drag_v1 global"; return; } + } else if (!connection->org_kde_kwin_idle_ && + strcmp(interface, "org_kde_kwin_idle") == 0) { + auto idle = wl::Bind<struct org_kde_kwin_idle>( + registry, name, std::min(version, kMaxOrgKdeKwinIdleVersion)); + if (!idle) { + LOG(ERROR) << "Failed to bind to org_kde_kwin_idle global"; + return; + } + connection->org_kde_kwin_idle_ = + std::make_unique<OrgKdeKwinIdle>(idle.release(), connection); } connection->ScheduleFlush();
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h index 19dca2c1c5..99b99424 100644 --- a/ui/ozone/platform/wayland/host/wayland_connection.h +++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -32,6 +32,7 @@ namespace ui { class DeviceHotplugEventObserver; +class OrgKdeKwinIdle; class WaylandBufferManagerHost; class WaylandCursor; class WaylandCursorBufferListener; @@ -187,6 +188,8 @@ GtkShell1* gtk_shell1() { return gtk_shell1_.get(); } + OrgKdeKwinIdle* org_kde_kwin_idle() { return org_kde_kwin_idle_.get(); } + ZwpPrimarySelectionDeviceManager* zwp_primary_selection_device_manager() const { return zwp_primary_selection_device_manager_.get(); @@ -308,6 +311,9 @@ std::unique_ptr<GtkShell1> gtk_shell1_; + // Objects specific to KDE Plasma desktop environment. + std::unique_ptr<OrgKdeKwinIdle> org_kde_kwin_idle_; + std::unique_ptr<WaylandDataDragController> data_drag_controller_; std::unique_ptr<WaylandWindowDragController> window_drag_controller_;
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc index d59919b1..541702c 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/containers/flat_set.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/file_info.h" @@ -729,9 +730,18 @@ origin_window->SetPointerFocus(restored_focus); } +// TODO(crbug.com/1211689): Flaky on LaCrOS. +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#define MAYBE_PopupRequestCreatesAuxiliaryWindow \ + DISABLED_PopupRequestCreatesAuxiliaryWindow +#else +#define MAYBE_PopupRequestCreatesAuxiliaryWindow \ + PopupRequestCreatesAuxiliaryWindow +#endif // Ensures that requests to create a |PlatformWindowType::kPopup| during drag // sessions return wl_subsurface-backed windows. -TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesAuxiliaryWindow) { +TEST_P(WaylandDataDragControllerTest, + MAYBE_PopupRequestCreatesAuxiliaryWindow) { auto* origin_window = window_.get(); const bool restored_focus = origin_window->has_pointer_focus(); FocusAndPressLeftPointerButton(origin_window, &delegate_);
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc index 238ed43..9c761af9 100644 --- a/ui/ozone/platform/wayland/host/wayland_screen.cc +++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -19,6 +19,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/wayland/host/org_kde_kwin_idle.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_cursor_position.h" @@ -246,6 +247,13 @@ } base::TimeDelta WaylandScreen::CalculateIdleTime() const { + // Try the org_kde_kwin_idle Wayland protocol extension (KWin). + if (const auto* kde_idle = connection_->org_kde_kwin_idle()) { + const auto idle_time = kde_idle->GetIdleTime(); + if (idle_time) + return *idle_time; + } + #if defined(USE_DBUS) // Try the org.gnome.Mutter.IdleMonitor D-Bus service (Mutter). if (!org_gnome_mutter_idle_monitor_) @@ -256,7 +264,6 @@ return *idle_time; #endif // defined(USE_DBUS) - // Try the org_kde_kwin_idle Wayland protocol extension (KWin). NOTIMPLEMENTED_LOG_ONCE(); // No providers. Return 0 which means the system never gets idle.
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn index 348ea49..587b5f1 100644 --- a/ui/views/examples/BUILD.gn +++ b/ui/views/examples/BUILD.gn
@@ -11,6 +11,8 @@ testonly = true sources = [ + "animation_builder.cc", + "animation_builder.h", "animation_example.cc", "animation_example.h", "ax_example.cc",
diff --git a/ui/views/examples/animation_builder.cc b/ui/views/examples/animation_builder.cc new file mode 100644 index 0000000..4c26439 --- /dev/null +++ b/ui/views/examples/animation_builder.cc
@@ -0,0 +1,124 @@ +// 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 <utility> + +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_element.h" +#include "ui/compositor/layer_animation_sequence.h" +#include "ui/compositor/layer_animator.h" +#include "ui/views/examples/animation_builder.h" + +namespace views { + +AnimationBuilder::AnimationBuilder() = default; + +AnimationBuilder::~AnimationBuilder() { + for (auto& animation : animation_sequences_) { + View* view = animation.first; + if (!view->layer()) + view->SetPaintToLayer(); + std::vector<ui::LayerAnimationSequence*> sequences; + for (auto& s : animation.second) { + sequences.push_back(s.release()); + } + view->layer()->GetAnimator()->StartTogether(sequences); + } +} + +AnimationBuilder& AnimationBuilder::SetDuration(base::TimeDelta duration) { + if (in_sequence_) + old_duration_ = duration_; + duration_ = duration; + return *this; +} + +AnimationBuilder& AnimationBuilder::SetOpacity(View* view, + float target_opacity) { + // Create an entry if it doesn't exist. + if (animation_sequences_.find(view) == animation_sequences_.end()) + CreateNewEntry(view); + + AddAnimation(view, ui::LayerAnimationElement::CreateOpacityElement( + target_opacity, duration_)); + return *this; +} + +AnimationBuilder& AnimationBuilder::SetRoundedCorners( + View* view, + gfx::RoundedCornersF& rounded_corners) { + // Create an entry if it doesn't exist. + if (animation_sequences_.find(view) == animation_sequences_.end()) + CreateNewEntry(view); + + AddAnimation(view, ui::LayerAnimationElement::CreateRoundedCornersElement( + rounded_corners, duration_)); + return *this; +} + +AnimationBuilder& AnimationBuilder::Repeat() { + // Go through all empty sequences added in StartSequence() and set the correct + // repeating behavior. + if (in_sequence_) { + is_sequence_repeating_ = true; + for (auto& animation : animation_sequences_) { + animation_sequences_[animation.first].back()->set_is_repeating( + is_sequence_repeating_); + } + } + return *this; +} + +AnimationBuilder& AnimationBuilder::StartSequence() { + in_sequence_ = true; + // Add an empty sequence for all existing views. + for (auto& animation : animation_sequences_) { + std::unique_ptr<ui::LayerAnimationSequence> new_sequence = + std::make_unique<ui::LayerAnimationSequence>(); + animation_sequences_[animation.first].push_back(std::move(new_sequence)); + } + return *this; +} + +AnimationBuilder& AnimationBuilder::EndSequence() { + in_sequence_ = false; + is_sequence_repeating_ = false; + duration_ = old_duration_; + // Remove sequences that were not added to. + for (auto& animation : animation_sequences_) { + if (animation_sequences_[animation.first].back()->size() == 0) { + animation_sequences_[animation.first].pop_back(); + } + } + return *this; +} + +void AnimationBuilder::CreateNewEntry(View* view) { + animation_sequences_[view] = + std::vector<std::unique_ptr<ui::LayerAnimationSequence>>(); + if (in_sequence_) { + // New empty sequence has not been added in StartSequence yet + std::unique_ptr<ui::LayerAnimationSequence> new_sequence = + std::make_unique<ui::LayerAnimationSequence>(); + new_sequence->set_is_repeating(is_sequence_repeating_); + animation_sequences_[view].push_back(std::move(new_sequence)); + } +} + +void AnimationBuilder::AddAnimation( + View* view, + std::unique_ptr<ui::LayerAnimationElement> element) { + if (in_sequence_) { + // Add to existing sequence so that these animations are done sequentially + animation_sequences_[view].back()->AddElement(std::move(element)); + } else { + // Create a new sequence with one element + std::unique_ptr<ui::LayerAnimationSequence> new_sequence = + std::make_unique<ui::LayerAnimationSequence>(); + new_sequence->AddElement(std::move(element)); + animation_sequences_[view].push_back(std::move(new_sequence)); + } +} + +} // namespace views
diff --git a/ui/views/examples/animation_builder.h b/ui/views/examples/animation_builder.h new file mode 100644 index 0000000..5e3d23f5 --- /dev/null +++ b/ui/views/examples/animation_builder.h
@@ -0,0 +1,58 @@ +// 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 UI_VIEWS_EXAMPLES_ANIMATION_BUILDER_H_ +#define UI_VIEWS_EXAMPLES_ANIMATION_BUILDER_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "ui/views/view.h" + +namespace ui { +class LayerAnimationSequence; +class LayerAnimationElement; +} // namespace ui + +namespace views { + +// This AnimationBuilder API is currently in the experimental phase and only +// used within ui/views/examples/. +// This class should eventually be moved out of ui/views/examples/ if we proceed +// with this implementation. +class AnimationBuilder { + public: + AnimationBuilder(); + ~AnimationBuilder(); + + AnimationBuilder& SetDuration(base::TimeDelta duration); + + // These methods should be changed to OnSetXXX if we integrate with the View + // base class. + AnimationBuilder& SetOpacity(View* view, float target_opacity); + AnimationBuilder& SetRoundedCorners(views::View* view, + gfx::RoundedCornersF& rounded_corners); + + // No effect if called before StartSequence(); + AnimationBuilder& Repeat(); + // Currently does not support nested sequences + AnimationBuilder& StartSequence(); + AnimationBuilder& EndSequence(); + + private: + void CreateNewEntry(View* view); + void AddAnimation(View* view, + std::unique_ptr<ui::LayerAnimationElement> element); + + std::map<View*, std::vector<std::unique_ptr<ui::LayerAnimationSequence>>> + animation_sequences_; + bool in_sequence_ = false; + bool is_sequence_repeating_ = false; + base::TimeDelta duration_ = base::TimeDelta::FromSeconds(1); + base::TimeDelta old_duration_; +}; +} // namespace views + +#endif // UI_VIEWS_EXAMPLES_ANIMATION_BUILDER_H_
diff --git a/ui/views/examples/animation_example.cc b/ui/views/examples/animation_example.cc index cff22c5..7adda485 100644 --- a/ui/views/examples/animation_example.cc +++ b/ui/views/examples/animation_example.cc
@@ -19,8 +19,10 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/size.h" #include "ui/views/background.h" +#include "ui/views/examples/animation_builder.h" #include "ui/views/layout/animating_layout_manager.h" #include "ui/views/layout/layout_manager_base.h" #include "ui/views/layout/layout_provider.h" @@ -63,14 +65,6 @@ layer()->GetAnimator()->set_tween_type(gfx::Tween::EASE_IN_OUT); layer()->GetAnimator()->set_preemption_strategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - auto opacity_sequence = std::make_unique<ui::LayerAnimationSequence>(); - opacity_sequence->set_is_repeating(true); - opacity_sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement( - 0.4f, base::TimeDelta::FromSeconds(2))); - opacity_sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement( - 0.9f, base::TimeDelta::FromSeconds(2))); - layer()->GetAnimator()->StartAnimation(opacity_sequence.release()); } void AnimatingSquare::OnPaint(gfx::Canvas* canvas) { @@ -155,6 +149,21 @@ container->SetLayoutManager(std::make_unique<SquaresLayoutManager>()); for (size_t i = 0; i < 5; ++i) container->AddChildView(std::make_unique<AnimatingSquare>(i)); + + { + gfx::RoundedCornersF rounded_corners(12.0f, 12.0f, 12.0f, 12.0f); + AnimationBuilder b; + for (auto* view : container->children()) { + b.SetDuration(base::TimeDelta::FromSeconds(10)) + .SetRoundedCorners(view, rounded_corners) + .StartSequence() + .Repeat() + .SetDuration(base::TimeDelta::FromSeconds(2)) + .SetOpacity(view, 0.4f) + .SetOpacity(view, 0.9f) + .EndSequence(); + } + } } } // namespace examples
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html index 72beca8..da3132b4 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html
@@ -15,7 +15,7 @@ :host { display: flex; justify-content: flex-end; - padding: 10px 0; + padding: 10px 0 20px 0; } #forward:focus {
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html index a20ab4e..95d7ced 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_dialog.html
@@ -10,8 +10,13 @@ <template> <style include="cr-shared-style iron-flex"> :host { + --cr-dialog-body-padding-horizontal: 24px; + --cr-dialog-button-container-padding-bottom: 20px; + --cr-dialog-button-container-padding-horizontal: 24px; --cr-dialog-width: 320px; --cr-dialog-title-slot-padding-bottom: 12px; + --cr-dialog-title-slot-padding-end: 24px; + --cr-dialog-title-slot-padding-start: 24px; --cr-dialog-title-font-size: calc(16 / 13 * 100%); } @@ -33,6 +38,9 @@ #qrCodeCanvas { display: block; margin: 20px auto 16px auto; + max-width: calc(var(--cr-dialog-width) - + var(--cr-dialog-title-slot-padding-start) - + var(--cr-dialog-title-slot-padding-end)); } #eid {
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html index 66a36e9..42af22f 100644 --- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -65,7 +65,7 @@ :host ::slotted([slot=body]) { color: var(--cr-secondary-text-color); - padding: 0 20px; + padding: 0 var(--cr-dialog-body-padding-horizontal, 20px); } :host ::slotted([slot=title]) { @@ -83,9 +83,9 @@ :host ::slotted([slot=button-container]) { display: flex; justify-content: flex-end; - padding-bottom: 16px; - padding-inline-end: 16px; - padding-inline-start: 16px; + padding-bottom: var(--cr-dialog-button-container-padding-bottom, 16px); + padding-inline-end: var(--cr-dialog-button-container-padding-horizontal, 16px); + padding-inline-start: var(--cr-dialog-button-container-padding-horizontal, 16px); padding-top: 24px; }
diff --git a/url/ipc/url_param_traits_unittest.cc b/url/ipc/url_param_traits_unittest.cc index 0fbddc7..a49203d 100644 --- a/url/ipc/url_param_traits_unittest.cc +++ b/url/ipc/url_param_traits_unittest.cc
@@ -11,63 +11,128 @@ #include "url/gurl.h" #include "url/ipc/url_param_traits.h" +namespace { + +GURL BounceUrl(const GURL& input) { + IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<GURL>::Write(&msg, input); + + GURL output; + base::PickleIterator iter(msg); + EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); + + return output; +} + +void ExpectSerializationRoundtrips(const GURL& input) { + SCOPED_TRACE(testing::Message() + << "Input GURL: " << input.possibly_invalid_spec()); + GURL output = BounceUrl(input); + + // We want to test each component individually to make sure its range was + // correctly serialized and deserialized, not just the spec. + EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec()); + EXPECT_EQ(input.is_valid(), output.is_valid()); + EXPECT_EQ(input.scheme(), output.scheme()); + EXPECT_EQ(input.username(), output.username()); + EXPECT_EQ(input.password(), output.password()); + EXPECT_EQ(input.host(), output.host()); + EXPECT_EQ(input.port(), output.port()); + EXPECT_EQ(input.path(), output.path()); + EXPECT_EQ(input.query(), output.query()); + EXPECT_EQ(input.ref(), output.ref()); +} + +} // namespace + // Tests that serialize/deserialize correctly understand each other. -TEST(IPCMessageTest, Serialize) { +TEST(IPCMessageTest, SerializeGurl_Basic) { const char* serialize_cases[] = { "http://www.google.com/", "http://user:pass@host.com:888/foo;bar?baz#nop", }; - for (size_t i = 0; i < base::size(serialize_cases); i++) { - GURL input(serialize_cases[i]); - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<GURL>::Write(&msg, input); - - GURL output; - base::PickleIterator iter(msg); - EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - - // We want to test each component individually to make sure its range was - // correctly serialized and deserialized, not just the spec. - EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec()); - EXPECT_EQ(input.is_valid(), output.is_valid()); - EXPECT_EQ(input.scheme(), output.scheme()); - EXPECT_EQ(input.username(), output.username()); - EXPECT_EQ(input.password(), output.password()); - EXPECT_EQ(input.host(), output.host()); - EXPECT_EQ(input.port(), output.port()); - EXPECT_EQ(input.path(), output.path()); - EXPECT_EQ(input.query(), output.query()); - EXPECT_EQ(input.ref(), output.ref()); + for (const char* test_input : serialize_cases) { + SCOPED_TRACE(testing::Message() << "Test input: " << test_input); + GURL input(test_input); + ExpectSerializationRoundtrips(input); } +} - // Test an excessively long GURL. - { - const std::string url = std::string("http://example.org/").append( - url::kMaxURLChars + 1, 'a'); - GURL input(url.c_str()); - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<GURL>::Write(&msg, input); +// Test of an excessively long GURL. +TEST(IPCMessageTest, SerializeGurl_ExcessivelyLong) { + const std::string url = + std::string("http://example.org/").append(url::kMaxURLChars + 1, 'a'); + GURL input(url.c_str()); + GURL output = BounceUrl(input); + EXPECT_TRUE(output.is_empty()); +} - GURL output; - base::PickleIterator iter(msg); - EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - EXPECT_TRUE(output.is_empty()); - } +// Test of an invalid GURL. +TEST(IPCMessageTest, SerializeGurl_InvalidUrl) { + IPC::Message msg; + msg.WriteString("#inva://idurl/"); + GURL output; + base::PickleIterator iter(msg); + EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); +} - // Test an invalid GURL. - { - IPC::Message msg; - msg.WriteString("#inva://idurl/"); - GURL output; - base::PickleIterator iter(msg); - EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); - } - - // Also test the corrupt case. +// Test of a corrupt deserialization input. +TEST(IPCMessageTest, SerializeGurl_CorruptPayload) { IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); msg.WriteInt(99); GURL output; base::PickleIterator iter(msg); EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output)); } + +// Test for the GURL testcase based on https://crbug.com/1214098 (which in turn +// was based on ContentSecurityPolicyBrowserTest.FileURLs). +TEST(IPCMessageTest, SerializeGurl_WindowsDriveInPathReplacement) { + GURL url1("file://hostname/"); + ExpectSerializationRoundtrips(url1); + EXPECT_EQ("/", url1.path()); + EXPECT_EQ("hostname", url1.host()); + + // Use GURL::Replacement to create a GURL with 1) a path that starts with a C: + // drive letter and 2) has a non-empty hostname (inherited from `url1` above). + // Without GURL::Replacement we would just get `url2` below, with an empty + // hostname, because of how DoParseUNC resets the hostname on Win32 (for more + // details see https://crbug.com/1214098#c4). + GURL::Replacements repl; + const std::string kNewPath = "/C:/dir/file.txt"; + repl.SetPath(kNewPath.c_str(), url::Component(0, kNewPath.length())); + GURL url1_with_replaced_path = url1.ReplaceComponents(repl); + EXPECT_EQ(kNewPath, url1_with_replaced_path.path()); + EXPECT_EQ("hostname", url1_with_replaced_path.host()); + +#ifdef WIN32 + // TODO(https://crbug.com/1214098): All GURLs should round-trip when bounced + // through IPC, but this doesn't work for `url1_with_replaced_path` on + // Windows. + GURL roundtrip = BounceUrl(url1_with_replaced_path); + EXPECT_NE(roundtrip.host(), url1_with_replaced_path.host()); +#else + // This is the MAIN VERIFICATION in this test. The fact that this + // verification fails on Windows is the bug tracked in + // https://crbug.com/1214098. + ExpectSerializationRoundtrips(url1_with_replaced_path); +#endif + + // On Windows, `url1_with_replaced_path` will round-trip as `url2`. (There is + // nothing wrong with `url2` - its serialization round-trips just fine; the + // test assertions below just help explain the lack of round-tripping of + // `url1_with_replaced_path` above.) + GURL url2("file://hostname/C:/dir/file.txt"); + ExpectSerializationRoundtrips(url2); +#ifdef WIN32 + EXPECT_EQ(url2.spec(), url1_with_replaced_path.spec()); + EXPECT_EQ(url2.path(), url1_with_replaced_path.path()); + EXPECT_EQ(url2.host(), url1_with_replaced_path.host()); + EXPECT_EQ("/C:/dir/file.txt", url2.path()); + EXPECT_EQ("", url2.host()); +#else + EXPECT_EQ("/C:/dir/file.txt", url2.path()); + EXPECT_EQ("hostname", url2.host()); +#endif +}
diff --git a/url/mojom/url_gurl_mojom_traits_unittest.cc b/url/mojom/url_gurl_mojom_traits_unittest.cc index f0b1c60b..5be941c 100644 --- a/url/mojom/url_gurl_mojom_traits_unittest.cc +++ b/url/mojom/url_gurl_mojom_traits_unittest.cc
@@ -32,21 +32,21 @@ mojo::Receiver<UrlTest> receiver_; }; -// Mojo version of chrome IPC test in url/ipc/url_param_traits_unittest.cc. -TEST(MojoGURLStructTraitsTest, Basic) { - base::test::SingleThreadTaskEnvironment task_environment; +class MojoGURLStructTraitsTest : public ::testing::Test { + public: + MojoGURLStructTraitsTest() + : url_test_impl_(url_test_remote_.BindNewPipeAndPassReceiver()) {} - mojo::Remote<mojom::UrlTest> remote; - UrlTestImpl impl(remote.BindNewPipeAndPassReceiver()); - - const char* serialize_cases[] = { - "http://www.google.com/", "http://user:pass@host.com:888/foo;bar?baz#nop", - }; - - for (size_t i = 0; i < base::size(serialize_cases); i++) { - GURL input(serialize_cases[i]); + GURL BounceUrl(const GURL& input) { GURL output; - EXPECT_TRUE(remote->BounceUrl(input, &output)); + EXPECT_TRUE(url_test_remote_->BounceUrl(input, &output)); + return output; + } + + void ExpectSerializationRoundtrips(const GURL& input) { + SCOPED_TRACE(testing::Message() + << "Input GURL: " << input.possibly_invalid_spec()); + GURL output = BounceUrl(input); // We want to test each component individually to make sure its range was // correctly serialized and deserialized, not just the spec. @@ -62,22 +62,97 @@ EXPECT_EQ(input.ref(), output.ref()); } - // Test an excessively long GURL. - { - const std::string url = - std::string("http://example.org/").append(kMaxURLChars + 1, 'a'); - GURL input(url.c_str()); - GURL output; - EXPECT_TRUE(remote->BounceUrl(input, &output)); - EXPECT_TRUE(output.is_empty()); + Origin BounceOrigin(const Origin& input) { + Origin output; + EXPECT_TRUE(url_test_remote_->BounceOrigin(input, &output)); + return output; } - // Test basic Origin serialization. + private: + base::test::SingleThreadTaskEnvironment task_environment; + mojo::Remote<mojom::UrlTest> url_test_remote_; + UrlTestImpl url_test_impl_; +}; + +// Mojo version of chrome IPC test in url/ipc/url_param_traits_unittest.cc. +TEST_F(MojoGURLStructTraitsTest, Basic) { + const char* serialize_cases[] = { + "http://www.google.com/", + "http://user:pass@host.com:888/foo;bar?baz#nop", + }; + + for (const char* test_input : serialize_cases) { + SCOPED_TRACE(testing::Message() << "Test input: " << test_input); + GURL input(test_input); + ExpectSerializationRoundtrips(input); + } +} + +// Test of an excessively long GURL. +TEST_F(MojoGURLStructTraitsTest, ExcessivelyLongUrl) { + const std::string url = + std::string("http://example.org/").append(kMaxURLChars + 1, 'a'); + GURL input(url.c_str()); + GURL output = BounceUrl(input); + EXPECT_TRUE(output.is_empty()); +} + +// Test for the GURL testcase based on https://crbug.com/1214098 (which in turn +// was based on ContentSecurityPolicyBrowserTest.FileURLs). +TEST_F(MojoGURLStructTraitsTest, WindowsDriveInPathReplacement) { + GURL url1("file://hostname/"); + ExpectSerializationRoundtrips(url1); + EXPECT_EQ("/", url1.path()); + EXPECT_EQ("hostname", url1.host()); + + // Use GURL::Replacement to create a GURL with 1) a path that starts with a C: + // drive letter and 2) has a non-empty hostname (inherited from `url1` above). + // Without GURL::Replacement we would just get `url2` below, with an empty + // hostname, because of how DoParseUNC resets the hostname on Win32 (for more + // details see https://crbug.com/1214098#c4). + GURL::Replacements repl; + const std::string kNewPath = "/C:/dir/file.txt"; + repl.SetPath(kNewPath.c_str(), url::Component(0, kNewPath.length())); + GURL url1_with_replaced_path = url1.ReplaceComponents(repl); + EXPECT_EQ(kNewPath, url1_with_replaced_path.path()); + EXPECT_EQ("hostname", url1_with_replaced_path.host()); + +#ifdef WIN32 + // TODO(https://crbug.com/1214098): All GURLs should round-trip when bounced + // through IPC, but this doesn't work for `url1_with_replaced_path` on + // Windows. + GURL roundtrip = BounceUrl(url1_with_replaced_path); + EXPECT_NE(roundtrip.host(), url1_with_replaced_path.host()); +#else + // This is the MAIN VERIFICATION in this test. The fact that this + // verification fails on Windows is the bug tracked in + // https://crbug.com/1214098. + ExpectSerializationRoundtrips(url1_with_replaced_path); +#endif + + // On Windows, IPC will serialize/deserialze `url1_with_replaced_path` as + // `url2` (i.e. it won't round-trip the URL spec). The test assertions below + // help illustrate why we can't assert ExpectSerializationRoundtrips above (on + // Windows). + EXPECT_EQ("file://hostname/C:/dir/file.txt", url1_with_replaced_path.spec()); + GURL url2(url1_with_replaced_path.spec()); +#ifdef WIN32 + EXPECT_NE(url2.spec(), url1_with_replaced_path.spec()); + EXPECT_EQ("", url2.host()); +#else + EXPECT_EQ(url2.spec(), url1_with_replaced_path.spec()); + EXPECT_EQ("hostname", url2.host()); +#endif + EXPECT_EQ(url2.path(), url1_with_replaced_path.path()); + ExpectSerializationRoundtrips(url2); +} + +// Test of basic Origin serialization. +TEST_F(MojoGURLStructTraitsTest, OriginSerialization) { Origin non_unique = Origin::UnsafelyCreateTupleOriginWithoutNormalization( "http", "www.google.com", 80) .value(); - Origin output; - EXPECT_TRUE(remote->BounceOrigin(non_unique, &output)); + Origin output = BounceOrigin(non_unique); EXPECT_EQ(non_unique, output); EXPECT_FALSE(output.opaque()); @@ -86,11 +161,10 @@ EXPECT_NE(unique1, unique2); EXPECT_NE(unique2, unique1); EXPECT_NE(unique2, non_unique); - EXPECT_TRUE(remote->BounceOrigin(unique1, &output)); + output = BounceOrigin(unique1); EXPECT_TRUE(output.opaque()); EXPECT_EQ(unique1, output); - Origin output2; - EXPECT_TRUE(remote->BounceOrigin(unique2, &output2)); + Origin output2 = BounceOrigin(unique2); EXPECT_EQ(unique2, output2); EXPECT_NE(unique2, output); EXPECT_NE(unique1, output2); @@ -98,7 +172,7 @@ Origin normalized = Origin::CreateFromNormalizedTuple("http", "www.google.com", 80); EXPECT_EQ(normalized, non_unique); - EXPECT_TRUE(remote->BounceOrigin(normalized, &output)); + output = BounceOrigin(normalized); EXPECT_EQ(normalized, output); EXPECT_EQ(non_unique, output); EXPECT_FALSE(output.opaque());
diff --git a/url/origin_abstract_tests.h b/url/origin_abstract_tests.h index 26190a0b..89ed9ab02 100644 --- a/url/origin_abstract_tests.h +++ b/url/origin_abstract_tests.h
@@ -372,6 +372,15 @@ {"file://example.com/etc/passwd", {"file", "example.com", 0}}, {"file:///", {"file", "", 0}}, +#ifdef WIN32 + // TODO(https://crbug.com/1214098): Consider unifying URL parsing behavior + // on all platforms (or at least make sure that serialization always + // round-trips - see https://crbug.com/1214098). + {"file://hostname/C:/dir/file.txt", {"file", "", 0}}, +#else + {"file://hostname/C:/dir/file.txt", {"file", "hostname", 0}}, +#endif + // HTTP URLs {"http://example.com/", {"http", "example.com", 80}}, {"http://example.com:80/", {"http", "example.com", 80}},
diff --git a/weblayer/shell/android/shell_apk/AndroidManifest.xml b/weblayer/shell/android/shell_apk/AndroidManifest.xml index a7734e0..8b47b41 100644 --- a/weblayer/shell/android/shell_apk/AndroidManifest.xml +++ b/weblayer/shell/android/shell_apk/AndroidManifest.xml
@@ -7,6 +7,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" package="org.chromium.weblayer.shell"> <application android:label="WebLayer shell" @@ -63,6 +64,14 @@ <meta-data android:name="org.chromium.weblayer.ENABLE_LOGGING_OF_JS_CONSOLE_MESSAGES" android:value="true"/> + <!-- Disables at startup init of Emoji2. See http://crbug.com/1205141 --> + <provider + android:authorities="org.chromium.weblayer.shell.androidx-startup" + android:name="androidx.startup.InitializationProvider" + android:exported="false" + tools:node="remove"> + </provider> + {% if weblayer_package is defined %} <meta-data android:name="org.chromium.weblayer.WebLayerPackage" android:value="{{ weblayer_package }}"/>